@lamalibre/create-lamaste 4.0.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 (270) hide show
  1. package/LICENSE.md +118 -0
  2. package/README.md +114 -0
  3. package/bin/create-lamaste.js +15 -0
  4. package/package.json +54 -0
  5. package/scripts/bundle-vendor.js +110 -0
  6. package/scripts/lamaste-cert-info +62 -0
  7. package/scripts/lamaste-certbot +96 -0
  8. package/scripts/lamaste-priv +693 -0
  9. package/src/index.js +646 -0
  10. package/src/lib/accounts.js +86 -0
  11. package/src/lib/binaries.js +137 -0
  12. package/src/lib/cert-help-page.js +160 -0
  13. package/src/lib/env.js +132 -0
  14. package/src/lib/http-redirect.js +38 -0
  15. package/src/lib/ownership.js +231 -0
  16. package/src/lib/relay-services.js +103 -0
  17. package/src/lib/secrets.js +19 -0
  18. package/src/lib/service-config.js +311 -0
  19. package/src/lib/summary.js +131 -0
  20. package/src/lib/wrappers.js +63 -0
  21. package/src/tasks/gatekeeper.js +233 -0
  22. package/src/tasks/harden.js +293 -0
  23. package/src/tasks/mtls.js +193 -0
  24. package/src/tasks/nginx.js +265 -0
  25. package/src/tasks/node.js +110 -0
  26. package/src/tasks/panel.js +408 -0
  27. package/src/tasks/redeploy.js +438 -0
  28. package/vendor/docs/00-introduction/how-it-works.md +447 -0
  29. package/vendor/docs/00-introduction/quickstart.md +472 -0
  30. package/vendor/docs/00-introduction/what-is-lamaste.md +112 -0
  31. package/vendor/docs/01-concepts/authentication.md +464 -0
  32. package/vendor/docs/01-concepts/authorization.md +242 -0
  33. package/vendor/docs/01-concepts/certificates.md +452 -0
  34. package/vendor/docs/01-concepts/dns-and-domains.md +343 -0
  35. package/vendor/docs/01-concepts/mtls.md +490 -0
  36. package/vendor/docs/01-concepts/nginx-reverse-proxy.md +540 -0
  37. package/vendor/docs/01-concepts/security-model.md +600 -0
  38. package/vendor/docs/01-concepts/tickets.md +414 -0
  39. package/vendor/docs/01-concepts/tunneling.md +367 -0
  40. package/vendor/docs/02-guides/agent-setup.md +194 -0
  41. package/vendor/docs/02-guides/certificate-management.md +341 -0
  42. package/vendor/docs/02-guides/cloud-provisioning.md +406 -0
  43. package/vendor/docs/02-guides/desktop-app-setup.md +226 -0
  44. package/vendor/docs/02-guides/disaster-recovery.md +464 -0
  45. package/vendor/docs/02-guides/first-tunnel.md +230 -0
  46. package/vendor/docs/02-guides/installation.md +393 -0
  47. package/vendor/docs/02-guides/managing-users.md +255 -0
  48. package/vendor/docs/02-guides/onboarding.md +244 -0
  49. package/vendor/docs/02-guides/standalone-plugin-with-tickets.md +375 -0
  50. package/vendor/docs/02-guides/static-sites.md +364 -0
  51. package/vendor/docs/03-architecture/e2e-three-vm-sequences.md +457 -0
  52. package/vendor/docs/03-architecture/installer-flow.md +151 -0
  53. package/vendor/docs/03-architecture/installer.md +445 -0
  54. package/vendor/docs/03-architecture/management-flow.md +288 -0
  55. package/vendor/docs/03-architecture/nginx-configuration.md +830 -0
  56. package/vendor/docs/03-architecture/onboarding-flow.md +164 -0
  57. package/vendor/docs/03-architecture/overview.md +541 -0
  58. package/vendor/docs/03-architecture/panel-client.md +416 -0
  59. package/vendor/docs/03-architecture/panel-server.md +695 -0
  60. package/vendor/docs/03-architecture/state-management.md +529 -0
  61. package/vendor/docs/03-architecture/system-overview.md +167 -0
  62. package/vendor/docs/04-api-reference/certificates.md +1141 -0
  63. package/vendor/docs/04-api-reference/gatekeeper.md +592 -0
  64. package/vendor/docs/04-api-reference/onboarding.md +473 -0
  65. package/vendor/docs/04-api-reference/overview.md +404 -0
  66. package/vendor/docs/04-api-reference/services.md +267 -0
  67. package/vendor/docs/04-api-reference/settings.md +343 -0
  68. package/vendor/docs/04-api-reference/sites.md +716 -0
  69. package/vendor/docs/04-api-reference/system.md +268 -0
  70. package/vendor/docs/04-api-reference/tickets.md +618 -0
  71. package/vendor/docs/04-api-reference/tunnels.md +417 -0
  72. package/vendor/docs/04-api-reference/users.md +333 -0
  73. package/vendor/docs/05-operations/backup-and-restore.md +342 -0
  74. package/vendor/docs/05-operations/monitoring.md +285 -0
  75. package/vendor/docs/05-operations/uninstalling.md +344 -0
  76. package/vendor/docs/05-operations/upgrades.md +270 -0
  77. package/vendor/docs/06-reference/config-files.md +1080 -0
  78. package/vendor/docs/06-reference/glossary.md +528 -0
  79. package/vendor/docs/06-reference/installer-flags.md +260 -0
  80. package/vendor/docs/06-reference/ports-and-services.md +244 -0
  81. package/vendor/docs/06-reference/troubleshooting.md +665 -0
  82. package/vendor/docs/_index.json +233 -0
  83. package/vendor/docs/gatekeeper-design.md +953 -0
  84. package/vendor/docs/package.json +15 -0
  85. package/vendor/docs/todo/lib-cli-desktop-refactor.md +641 -0
  86. package/vendor/gatekeeper/dist/boot.d.ts +1 -0
  87. package/vendor/gatekeeper/dist/boot.d.ts.map +1 -0
  88. package/vendor/gatekeeper/dist/boot.js +17 -0
  89. package/vendor/gatekeeper/dist/boot.js.map +1 -0
  90. package/vendor/gatekeeper/dist/cli/commands/access.d.ts +2 -0
  91. package/vendor/gatekeeper/dist/cli/commands/access.d.ts.map +1 -0
  92. package/vendor/gatekeeper/dist/cli/commands/access.js +33 -0
  93. package/vendor/gatekeeper/dist/cli/commands/access.js.map +1 -0
  94. package/vendor/gatekeeper/dist/cli/commands/grants.d.ts +2 -0
  95. package/vendor/gatekeeper/dist/cli/commands/grants.d.ts.map +1 -0
  96. package/vendor/gatekeeper/dist/cli/commands/grants.js +110 -0
  97. package/vendor/gatekeeper/dist/cli/commands/grants.js.map +1 -0
  98. package/vendor/gatekeeper/dist/cli/commands/groups.d.ts +2 -0
  99. package/vendor/gatekeeper/dist/cli/commands/groups.d.ts.map +1 -0
  100. package/vendor/gatekeeper/dist/cli/commands/groups.js +98 -0
  101. package/vendor/gatekeeper/dist/cli/commands/groups.js.map +1 -0
  102. package/vendor/gatekeeper/dist/cli/index.d.ts +3 -0
  103. package/vendor/gatekeeper/dist/cli/index.d.ts.map +1 -0
  104. package/vendor/gatekeeper/dist/cli/index.js +45 -0
  105. package/vendor/gatekeeper/dist/cli/index.js.map +1 -0
  106. package/vendor/gatekeeper/dist/index.d.ts +9 -0
  107. package/vendor/gatekeeper/dist/index.d.ts.map +1 -0
  108. package/vendor/gatekeeper/dist/index.js +13 -0
  109. package/vendor/gatekeeper/dist/index.js.map +1 -0
  110. package/vendor/gatekeeper/dist/lib/authz.d.ts +16 -0
  111. package/vendor/gatekeeper/dist/lib/authz.d.ts.map +1 -0
  112. package/vendor/gatekeeper/dist/lib/authz.js +42 -0
  113. package/vendor/gatekeeper/dist/lib/authz.js.map +1 -0
  114. package/vendor/gatekeeper/dist/lib/cache-bust.d.ts +15 -0
  115. package/vendor/gatekeeper/dist/lib/cache-bust.d.ts.map +1 -0
  116. package/vendor/gatekeeper/dist/lib/cache-bust.js +19 -0
  117. package/vendor/gatekeeper/dist/lib/cache-bust.js.map +1 -0
  118. package/vendor/gatekeeper/dist/lib/constants.d.ts +82 -0
  119. package/vendor/gatekeeper/dist/lib/constants.d.ts.map +1 -0
  120. package/vendor/gatekeeper/dist/lib/constants.js +79 -0
  121. package/vendor/gatekeeper/dist/lib/constants.js.map +1 -0
  122. package/vendor/gatekeeper/dist/lib/grants.d.ts +32 -0
  123. package/vendor/gatekeeper/dist/lib/grants.d.ts.map +1 -0
  124. package/vendor/gatekeeper/dist/lib/grants.js +314 -0
  125. package/vendor/gatekeeper/dist/lib/grants.js.map +1 -0
  126. package/vendor/gatekeeper/dist/lib/groups.d.ts +10 -0
  127. package/vendor/gatekeeper/dist/lib/groups.d.ts.map +1 -0
  128. package/vendor/gatekeeper/dist/lib/groups.js +247 -0
  129. package/vendor/gatekeeper/dist/lib/groups.js.map +1 -0
  130. package/vendor/gatekeeper/dist/lib/migration.d.ts +17 -0
  131. package/vendor/gatekeeper/dist/lib/migration.d.ts.map +1 -0
  132. package/vendor/gatekeeper/dist/lib/migration.js +79 -0
  133. package/vendor/gatekeeper/dist/lib/migration.js.map +1 -0
  134. package/vendor/gatekeeper/dist/lib/migrations/gatekeeper/0001_groups.sql +7 -0
  135. package/vendor/gatekeeper/dist/lib/migrations/gatekeeper/0002_access_grants.sql +14 -0
  136. package/vendor/gatekeeper/dist/lib/migrations/gatekeeper/0003_access_request_log.sql +9 -0
  137. package/vendor/gatekeeper/dist/lib/migrations/migrations/gatekeeper/0001_groups.sql +7 -0
  138. package/vendor/gatekeeper/dist/lib/migrations/migrations/gatekeeper/0002_access_grants.sql +14 -0
  139. package/vendor/gatekeeper/dist/lib/migrations/migrations/gatekeeper/0003_access_request_log.sql +9 -0
  140. package/vendor/gatekeeper/dist/lib/state-db.d.ts +16 -0
  141. package/vendor/gatekeeper/dist/lib/state-db.d.ts.map +1 -0
  142. package/vendor/gatekeeper/dist/lib/state-db.js +154 -0
  143. package/vendor/gatekeeper/dist/lib/state-db.js.map +1 -0
  144. package/vendor/gatekeeper/dist/lib/templates.d.ts +21 -0
  145. package/vendor/gatekeeper/dist/lib/templates.d.ts.map +1 -0
  146. package/vendor/gatekeeper/dist/lib/templates.js +151 -0
  147. package/vendor/gatekeeper/dist/lib/templates.js.map +1 -0
  148. package/vendor/gatekeeper/dist/lib/types.d.ts +178 -0
  149. package/vendor/gatekeeper/dist/lib/types.d.ts.map +1 -0
  150. package/vendor/gatekeeper/dist/lib/types.js +2 -0
  151. package/vendor/gatekeeper/dist/lib/types.js.map +1 -0
  152. package/vendor/gatekeeper/dist/server/index.d.ts +15 -0
  153. package/vendor/gatekeeper/dist/server/index.d.ts.map +1 -0
  154. package/vendor/gatekeeper/dist/server/index.js +251 -0
  155. package/vendor/gatekeeper/dist/server/index.js.map +1 -0
  156. package/vendor/gatekeeper/dist/server/routes/access-request.d.ts +7 -0
  157. package/vendor/gatekeeper/dist/server/routes/access-request.d.ts.map +1 -0
  158. package/vendor/gatekeeper/dist/server/routes/access-request.js +17 -0
  159. package/vendor/gatekeeper/dist/server/routes/access-request.js.map +1 -0
  160. package/vendor/gatekeeper/dist/server/routes/authz.d.ts +3 -0
  161. package/vendor/gatekeeper/dist/server/routes/authz.d.ts.map +1 -0
  162. package/vendor/gatekeeper/dist/server/routes/authz.js +279 -0
  163. package/vendor/gatekeeper/dist/server/routes/authz.js.map +1 -0
  164. package/vendor/gatekeeper/dist/server/routes/diagnostic.d.ts +13 -0
  165. package/vendor/gatekeeper/dist/server/routes/diagnostic.d.ts.map +1 -0
  166. package/vendor/gatekeeper/dist/server/routes/diagnostic.js +249 -0
  167. package/vendor/gatekeeper/dist/server/routes/diagnostic.js.map +1 -0
  168. package/vendor/gatekeeper/dist/server/routes/grants.d.ts +3 -0
  169. package/vendor/gatekeeper/dist/server/routes/grants.d.ts.map +1 -0
  170. package/vendor/gatekeeper/dist/server/routes/grants.js +112 -0
  171. package/vendor/gatekeeper/dist/server/routes/grants.js.map +1 -0
  172. package/vendor/gatekeeper/dist/server/routes/groups.d.ts +3 -0
  173. package/vendor/gatekeeper/dist/server/routes/groups.d.ts.map +1 -0
  174. package/vendor/gatekeeper/dist/server/routes/groups.js +139 -0
  175. package/vendor/gatekeeper/dist/server/routes/groups.js.map +1 -0
  176. package/vendor/gatekeeper/package.json +49 -0
  177. package/vendor/server/bin/lamaste-server.js +204 -0
  178. package/vendor/server/package.json +31 -0
  179. package/vendor/server/src/commands/certs.js +224 -0
  180. package/vendor/server/src/commands/chisel.js +132 -0
  181. package/vendor/server/src/commands/logs.js +49 -0
  182. package/vendor/server/src/commands/plugins.js +321 -0
  183. package/vendor/server/src/commands/reset-admin.js +478 -0
  184. package/vendor/server/src/commands/restart.js +94 -0
  185. package/vendor/server/src/commands/sites.js +257 -0
  186. package/vendor/server/src/commands/status.js +158 -0
  187. package/vendor/server/src/commands/tunnels.js +365 -0
  188. package/vendor/server/src/commands/uninstall.js +326 -0
  189. package/vendor/server/src/config.js +38 -0
  190. package/vendor/server/src/exec.js +26 -0
  191. package/vendor/server/src/logger.js +39 -0
  192. package/vendor/server/src/ndjson.js +56 -0
  193. package/vendor/server/src/panel-api.js +85 -0
  194. package/vendor/server/src/state.js +45 -0
  195. package/vendor/server-ui/dist/assets/index-B0nWuUyL.js +257 -0
  196. package/vendor/server-ui/dist/assets/index-BqWWFlTU.css +1 -0
  197. package/vendor/server-ui/dist/index.html +13 -0
  198. package/vendor/serverd/package.json +44 -0
  199. package/vendor/serverd/src/boot.js +13 -0
  200. package/vendor/serverd/src/index.js +191 -0
  201. package/vendor/serverd/src/lib/app-error.js +14 -0
  202. package/vendor/serverd/src/lib/authelia.js +85 -0
  203. package/vendor/serverd/src/lib/certbot.js +74 -0
  204. package/vendor/serverd/src/lib/chisel-args.js +6 -0
  205. package/vendor/serverd/src/lib/chisel-reconcile.js +232 -0
  206. package/vendor/serverd/src/lib/chisel-runtime.js +46 -0
  207. package/vendor/serverd/src/lib/chisel-users.js +109 -0
  208. package/vendor/serverd/src/lib/chisel.js +81 -0
  209. package/vendor/serverd/src/lib/config.js +190 -0
  210. package/vendor/serverd/src/lib/constants.js +8 -0
  211. package/vendor/serverd/src/lib/csr-signing.js +331 -0
  212. package/vendor/serverd/src/lib/enrollment.js +302 -0
  213. package/vendor/serverd/src/lib/files.js +19 -0
  214. package/vendor/serverd/src/lib/gatekeeper-client.js +135 -0
  215. package/vendor/serverd/src/lib/invite-page.js +281 -0
  216. package/vendor/serverd/src/lib/ip-utils.js +79 -0
  217. package/vendor/serverd/src/lib/migrations/state/0001_enrollment_tokens.sql +17 -0
  218. package/vendor/serverd/src/lib/migrations/state/0002_tickets.sql +70 -0
  219. package/vendor/serverd/src/lib/migrations/state/0003_plugins.sql +15 -0
  220. package/vendor/serverd/src/lib/migrations/state/0004_agents.sql +19 -0
  221. package/vendor/serverd/src/lib/mtls.js +795 -0
  222. package/vendor/serverd/src/lib/nginx.js +1090 -0
  223. package/vendor/serverd/src/lib/pki-paths.js +41 -0
  224. package/vendor/serverd/src/lib/pki-sign.js +103 -0
  225. package/vendor/serverd/src/lib/plugins.js +538 -0
  226. package/vendor/serverd/src/lib/push-install.js +390 -0
  227. package/vendor/serverd/src/lib/revocation.js +112 -0
  228. package/vendor/serverd/src/lib/services.js +131 -0
  229. package/vendor/serverd/src/lib/session.js +151 -0
  230. package/vendor/serverd/src/lib/state-db.js +130 -0
  231. package/vendor/serverd/src/lib/state.js +140 -0
  232. package/vendor/serverd/src/lib/storage.js +63 -0
  233. package/vendor/serverd/src/lib/system-stats.js +58 -0
  234. package/vendor/serverd/src/lib/tickets.js +1556 -0
  235. package/vendor/serverd/src/lib/totp.js +76 -0
  236. package/vendor/serverd/src/lib/tunnel-deps.js +41 -0
  237. package/vendor/serverd/src/lib/user-access-session.js +142 -0
  238. package/vendor/serverd/src/lib/user-access.js +52 -0
  239. package/vendor/serverd/src/middleware/errors.js +63 -0
  240. package/vendor/serverd/src/middleware/mtls.js +120 -0
  241. package/vendor/serverd/src/middleware/onboarding-guard.js +30 -0
  242. package/vendor/serverd/src/middleware/role-guard.js +58 -0
  243. package/vendor/serverd/src/middleware/twofa-session.js +65 -0
  244. package/vendor/serverd/src/middleware/user-access-session.js +52 -0
  245. package/vendor/serverd/src/routes/enrollment.js +120 -0
  246. package/vendor/serverd/src/routes/health.js +22 -0
  247. package/vendor/serverd/src/routes/invite.js +163 -0
  248. package/vendor/serverd/src/routes/management/agents.js +182 -0
  249. package/vendor/serverd/src/routes/management/certs.js +911 -0
  250. package/vendor/serverd/src/routes/management/gatekeeper-proxy.js +160 -0
  251. package/vendor/serverd/src/routes/management/identity.js +107 -0
  252. package/vendor/serverd/src/routes/management/invitations.js +166 -0
  253. package/vendor/serverd/src/routes/management/logs.js +218 -0
  254. package/vendor/serverd/src/routes/management/plugins.js +560 -0
  255. package/vendor/serverd/src/routes/management/services.js +63 -0
  256. package/vendor/serverd/src/routes/management/settings.js +325 -0
  257. package/vendor/serverd/src/routes/management/sites.js +522 -0
  258. package/vendor/serverd/src/routes/management/storage.js +192 -0
  259. package/vendor/serverd/src/routes/management/system.js +201 -0
  260. package/vendor/serverd/src/routes/management/tickets.js +457 -0
  261. package/vendor/serverd/src/routes/management/tunnels.js +709 -0
  262. package/vendor/serverd/src/routes/management/users.js +377 -0
  263. package/vendor/serverd/src/routes/management.js +36 -0
  264. package/vendor/serverd/src/routes/onboarding/dns.js +101 -0
  265. package/vendor/serverd/src/routes/onboarding/domain.js +42 -0
  266. package/vendor/serverd/src/routes/onboarding/index.js +18 -0
  267. package/vendor/serverd/src/routes/onboarding/provision.js +327 -0
  268. package/vendor/serverd/src/routes/onboarding/status.js +12 -0
  269. package/vendor/serverd/src/routes/plugin-router.js +79 -0
  270. package/vendor/serverd/src/routes/user-access.js +389 -0
@@ -0,0 +1,321 @@
1
+ /**
2
+ * lamaste-server plugins — Manage server-side plugins.
3
+ *
4
+ * Subcommands:
5
+ * list List installed plugins with status
6
+ * install <package> Install a plugin by npm package name
7
+ * enable <name> Enable a plugin
8
+ * disable <name> Disable a plugin
9
+ * uninstall <name> Remove a plugin (must be disabled first)
10
+ */
11
+
12
+ import chalk from 'chalk';
13
+ import { execa } from 'execa';
14
+ import {
15
+ readPlugins,
16
+ installPlugin,
17
+ enablePlugin,
18
+ disablePlugin,
19
+ uninstallPlugin,
20
+ } from '@lamalibre/lamaste/server';
21
+ import { STATE_DIR, PANEL_SERVICE } from '../config.js';
22
+ import { exec } from '../exec.js';
23
+ import { createLogger } from '../logger.js';
24
+ import { emit, emitStep, emitError, emitComplete, emitLog } from '../ndjson.js';
25
+
26
+ /**
27
+ * @param {string[]} args Subcommand args: ['list'] | ['install', '<pkg>'] | ...
28
+ * @param {{ json: boolean }} options
29
+ */
30
+ export async function runPlugins(args, { json }) {
31
+ const sub = args[0];
32
+
33
+ if (MUTATING.has(sub) && process.getuid?.() === 0) {
34
+ await runAsLamaste(args, { json });
35
+ await restartPanel(json);
36
+ return;
37
+ }
38
+
39
+ switch (sub) {
40
+ case 'list':
41
+ return listPlugins({ json });
42
+ case 'install':
43
+ return installPluginCmd(args[1], { json });
44
+ case 'enable':
45
+ return enablePluginCmd(args[1], { json });
46
+ case 'disable':
47
+ return disablePluginCmd(args[1], { json });
48
+ case 'uninstall':
49
+ return uninstallPluginCmd(args[1], { json });
50
+ default:
51
+ printPluginUsage();
52
+ process.exit(sub ? 1 : 0);
53
+ }
54
+ }
55
+
56
+ function printPluginUsage() {
57
+ const b = chalk.bold;
58
+ const c = chalk.cyan;
59
+ console.log(`
60
+ ${b('Usage:')} lamaste-server plugins <subcommand>
61
+
62
+ ${b('Subcommands:')}
63
+ ${c('list')} List installed plugins with status
64
+ ${c('install <package>')} Install a plugin (e.g. @lamalibre/herd-server)
65
+ ${c('enable <name>')} Enable a plugin
66
+ ${c('disable <name>')} Disable a plugin
67
+ ${c('uninstall <name>')} Remove a disabled plugin
68
+ `);
69
+ }
70
+
71
+ /**
72
+ * @param {{ json: boolean }} options
73
+ */
74
+ async function listPlugins({ json }) {
75
+ const registry = await readPlugins(STATE_DIR);
76
+ const plugins = registry.plugins;
77
+
78
+ if (json) {
79
+ emit({ plugins });
80
+ return;
81
+ }
82
+
83
+ if (plugins.length === 0) {
84
+ console.log('\n No plugins installed.\n');
85
+ return;
86
+ }
87
+
88
+ const b = chalk.bold;
89
+ const c = chalk.cyan;
90
+ const g = chalk.green;
91
+ const r = chalk.red;
92
+ const d = chalk.dim;
93
+
94
+ console.log('');
95
+ console.log(b(' Installed Plugins'));
96
+ console.log(d(' ' + '\u2500'.repeat(40)));
97
+
98
+ for (const p of plugins) {
99
+ const status = p.status === 'enabled' ? g('enabled') : r('disabled');
100
+ console.log(` ${c(p.name)} ${d(p.version)} ${status} ${d(p.packageName)}`);
101
+ }
102
+ console.log('');
103
+ }
104
+
105
+ /**
106
+ * @param {string | undefined} packageName
107
+ * @param {{ json: boolean }} options
108
+ */
109
+ async function installPluginCmd(packageName, { json }) {
110
+ if (!packageName) {
111
+ const msg = 'Usage: lamaste-server plugins install <package>';
112
+ if (json) emitError(msg);
113
+ else console.error(`\n ${msg}\n`);
114
+ process.exit(1);
115
+ }
116
+
117
+ const logger = createLogger({ json });
118
+
119
+ if (json) {
120
+ emitStep('install', 'running', `Installing ${packageName}`);
121
+ emitLog('info', `Fetching ${packageName} from the npm registry — this may take a moment.`);
122
+ } else {
123
+ process.stderr.write(` Installing ${chalk.cyan(packageName)}...`);
124
+ }
125
+
126
+ try {
127
+ const entry = await installPlugin({
128
+ packageName,
129
+ stateDir: STATE_DIR,
130
+ exec,
131
+ logger,
132
+ });
133
+
134
+ if (json) {
135
+ emitStep('install', 'complete');
136
+ emitComplete({ plugin: entry });
137
+ } else {
138
+ console.log(` ${chalk.green('ok')}`);
139
+ console.log(` Plugin ${chalk.cyan(entry.name)} installed (${chalk.dim('disabled')})`);
140
+ console.log(
141
+ ` Run ${chalk.cyan(`lamaste-server plugins enable ${entry.name}`)} to activate.`,
142
+ );
143
+ console.log('');
144
+ }
145
+
146
+ await restartPanel(json);
147
+ } catch (err) {
148
+ if (json) {
149
+ emitStep('install', 'failed', err.message);
150
+ emitError(err.message);
151
+ } else {
152
+ console.log(` ${chalk.red('failed')}`);
153
+ console.error(` ${chalk.red(err.message)}`);
154
+ }
155
+ process.exit(1);
156
+ }
157
+ }
158
+
159
+ /**
160
+ * @param {string | undefined} name
161
+ * @param {{ json: boolean }} options
162
+ */
163
+ async function enablePluginCmd(name, { json }) {
164
+ if (!name) {
165
+ const msg = 'Usage: lamaste-server plugins enable <name>';
166
+ if (json) emitError(msg);
167
+ else console.error(`\n ${msg}\n`);
168
+ process.exit(1);
169
+ }
170
+
171
+ const logger = createLogger({ json });
172
+
173
+ try {
174
+ await enablePlugin({ name, stateDir: STATE_DIR, logger });
175
+ if (json) {
176
+ emitComplete({ name, status: 'enabled' });
177
+ } else {
178
+ console.log(`\n Plugin ${chalk.cyan(name)} ${chalk.green('enabled')}.`);
179
+ }
180
+ await restartPanel(json);
181
+ } catch (err) {
182
+ if (json) emitError(err.message);
183
+ else console.error(`\n ${chalk.red(err.message)}\n`);
184
+ process.exit(1);
185
+ }
186
+ }
187
+
188
+ /**
189
+ * @param {string | undefined} name
190
+ * @param {{ json: boolean }} options
191
+ */
192
+ async function disablePluginCmd(name, { json }) {
193
+ if (!name) {
194
+ const msg = 'Usage: lamaste-server plugins disable <name>';
195
+ if (json) emitError(msg);
196
+ else console.error(`\n ${msg}\n`);
197
+ process.exit(1);
198
+ }
199
+
200
+ const logger = createLogger({ json });
201
+
202
+ try {
203
+ await disablePlugin({ name, stateDir: STATE_DIR, logger });
204
+ if (json) {
205
+ emitComplete({ name, status: 'disabled' });
206
+ } else {
207
+ console.log(`\n Plugin ${chalk.cyan(name)} ${chalk.red('disabled')}.`);
208
+ }
209
+ await restartPanel(json);
210
+ } catch (err) {
211
+ if (json) emitError(err.message);
212
+ else console.error(`\n ${chalk.red(err.message)}\n`);
213
+ process.exit(1);
214
+ }
215
+ }
216
+
217
+ /**
218
+ * @param {string | undefined} name
219
+ * @param {{ json: boolean }} options
220
+ */
221
+ async function uninstallPluginCmd(name, { json }) {
222
+ if (!name) {
223
+ const msg = 'Usage: lamaste-server plugins uninstall <name>';
224
+ if (json) emitError(msg);
225
+ else console.error(`\n ${msg}\n`);
226
+ process.exit(1);
227
+ }
228
+
229
+ const logger = createLogger({ json });
230
+
231
+ if (json) emitStep('uninstall', 'running', `Uninstalling ${name}`);
232
+ else process.stderr.write(` Uninstalling ${chalk.cyan(name)}...`);
233
+
234
+ try {
235
+ await uninstallPlugin({ name, stateDir: STATE_DIR, exec, logger });
236
+ if (json) {
237
+ emitStep('uninstall', 'complete');
238
+ emitComplete({ name, removed: true });
239
+ } else {
240
+ console.log(` ${chalk.green('ok')}`);
241
+ }
242
+ await restartPanel(json);
243
+ } catch (err) {
244
+ if (json) {
245
+ emitStep('uninstall', 'failed', err.message);
246
+ emitError(err.message);
247
+ } else {
248
+ console.log(` ${chalk.red('failed')}`);
249
+ console.error(` ${chalk.red(err.message)}`);
250
+ }
251
+ process.exit(1);
252
+ }
253
+ }
254
+
255
+ const MUTATING = new Set(['install', 'enable', 'disable', 'uninstall']);
256
+
257
+ /** Set on the child run as lamaste: the root parent restarts the panel. */
258
+ const CHILD_ENV = 'LAMALIBRE_LAMASTE_CLI_PLUGINS_CHILD';
259
+
260
+ /**
261
+ * Run a plugin subcommand as the lamaste user and wait for it.
262
+ *
263
+ * Plugin state (the npm tree, plugins.json, plugin data) lives in the
264
+ * lamaste-owned state directory. Running npm or writing files there as root
265
+ * would let whatever the panel left in that directory — a `.npmrc`, a
266
+ * symlink — steer root. As lamaste, it can only reach what the panel could
267
+ * already reach. Stays usable while the panel is down (disabling a plugin
268
+ * that keeps it from starting).
269
+ *
270
+ * @param {string[]} args
271
+ * @param {{ json: boolean }} options
272
+ */
273
+ async function runAsLamaste(args, { json }) {
274
+ const uid = Number.parseInt((await execa('id', ['-u', 'lamaste'])).stdout.trim(), 10);
275
+ const gid = Number.parseInt((await execa('id', ['-g', 'lamaste'])).stdout.trim(), 10);
276
+ const { exitCode } = await execa(
277
+ process.execPath,
278
+ [process.argv[1], 'plugins', ...args, ...(json ? ['--json'] : [])],
279
+ {
280
+ uid,
281
+ gid,
282
+ cwd: STATE_DIR,
283
+ stdio: 'inherit',
284
+ reject: false,
285
+ env: {
286
+ ...process.env,
287
+ [CHILD_ENV]: '1',
288
+ HOME: STATE_DIR,
289
+ USER: 'lamaste',
290
+ LOGNAME: 'lamaste',
291
+ npm_config_cache: `${STATE_DIR}/.npm`,
292
+ },
293
+ extendEnv: false,
294
+ },
295
+ );
296
+ if (exitCode !== 0) process.exit(exitCode ?? 1);
297
+ }
298
+
299
+ /**
300
+ * Restart the panel service after plugin changes.
301
+ * Plugin enable/disable/install/uninstall requires a panel restart to take effect.
302
+ * @param {boolean} json
303
+ */
304
+ async function restartPanel(json) {
305
+ // The child run as lamaste cannot; its root parent does.
306
+ if (process.env[CHILD_ENV] === '1') return;
307
+ try {
308
+ await execa('systemctl', ['restart', PANEL_SERVICE]);
309
+ if (!json) {
310
+ console.log(` Panel service restarted.`);
311
+ console.log('');
312
+ }
313
+ } catch (err) {
314
+ const msg = `Warning: panel restart failed: ${err.stderr || err.message}`;
315
+ if (!json) {
316
+ console.error(` ${chalk.yellow(msg)}`);
317
+ console.error(` You may need to restart manually: systemctl restart ${PANEL_SERVICE}`);
318
+ console.log('');
319
+ }
320
+ }
321
+ }