@helyx/cli 1.4.3 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,27 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.6.0
4
+
5
+ ### Minor Changes
6
+
7
+ - b698422: Add the optional `helyx envbuilder` command and generated starter npm script.
8
+ Preserve platform builder selections in build manifests and include standalone
9
+ batch, PowerShell or POSIX scripts only when selected. The guided builder runs
10
+ locally, checks input format, masks saved credentials and preserves encryption
11
+ keys and custom settings until the operator confirms saving.
12
+
13
+ ## 1.5.0
14
+
15
+ ### Minor Changes
16
+
17
+ - Publish the coordinated shared contracts, scheduler admission repair, command-root renaming and restricted-word policy support, database repositories and migrations, and module runtime corrections. Align compatible internal dependency bands so public consumers install the updated shared contracts. Preserve private Testing and Alpha release states.
18
+
19
+ ### Patch Changes
20
+
21
+ - Updated dependencies
22
+ - @helyx/config@1.6.0
23
+ - @helyx/database@2.5.0
24
+
3
25
  ## 1.4.3
4
26
 
5
27
  ### Patch Changes
package/README.md CHANGED
@@ -20,6 +20,12 @@ operation supports a local or hosted PostgreSQL or MySQL-compatible database.
20
20
  and performs the bot bootstrap, including core and installed-module migrations.
21
21
  `migrate` applies only core migrations and exits.
22
22
 
23
+ Generated starters also include the optional `npm run envbuilder` command.
24
+ After `npm ci`, it runs `helyx envbuilder`, a local guided `.env` builder with
25
+ no connection tests. Additional standalone Windows batch, PowerShell and
26
+ macOS/Linux scripts are included only when selected for the download. Setup
27
+ and startup remain independent.
28
+
23
29
  `doctor` checks the complete bot environment, connectivity, immutable core
24
30
  migration history, package metadata and selected module/engine compatibility
25
31
  without logging in to Discord or changing the database. It inspects module
package/dist/cli.js CHANGED
@@ -24,6 +24,10 @@ try {
24
24
  else if (command === "setup") {
25
25
  await setup();
26
26
  }
27
+ else if (command === "envbuilder") {
28
+ const builder = (await import(new URL("../templates/self-host/env-builder.mjs", import.meta.url).href));
29
+ await builder.runEnvironmentBuilder(process.argv[3]);
30
+ }
27
31
  else if (command === "self-host") {
28
32
  await runSelfHostCommand(process.argv.slice(3));
29
33
  }
@@ -141,6 +145,7 @@ function printHelp() {
141
145
 
142
146
  Commands:
143
147
  setup Create .env safely and explain the available hosting paths
148
+ envbuilder Optionally create or update .env with a local guided builder
144
149
  start Start the Helyx Discord bot
145
150
  migrate Apply core migrations for the selected database engine and exit
146
151
  doctor Validate environment, database schema and module packages
package/dist/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  export * from "./self-host/catalogue.js";
2
2
  export * from "./self-host/command.js";
3
3
  export * from "./self-host/database-adapters.js";
4
+ export * from "./self-host/environment-builders.js";
4
5
  export * from "./self-host/manifest.js";
5
6
  export * from "./self-host/project-generator.js";
6
7
  export * from "./self-host/update.js";
package/dist/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  export * from "./self-host/catalogue.js";
2
2
  export * from "./self-host/command.js";
3
3
  export * from "./self-host/database-adapters.js";
4
+ export * from "./self-host/environment-builders.js";
4
5
  export * from "./self-host/manifest.js";
5
6
  export * from "./self-host/project-generator.js";
6
7
  export * from "./self-host/update.js";
@@ -2,6 +2,7 @@ import { z } from "zod";
2
2
  export declare const selfHostCategories: readonly ["Community", "Safety", "Support & Staff", "Auto Tools", "Automation", "Engagement", "Gaming", "Insights", "Integrations"];
3
3
  export declare const selfHostReleaseStatusSchema: z.ZodEnum<{
4
4
  planned: "planned";
5
+ alpha: "alpha";
5
6
  testing: "testing";
6
7
  beta: "beta";
7
8
  live: "live";
@@ -35,6 +36,7 @@ export declare const selfHostModuleSchema: z.ZodObject<{
35
36
  }>;
36
37
  releaseStatus: z.ZodEnum<{
37
38
  planned: "planned";
39
+ alpha: "alpha";
38
40
  testing: "testing";
39
41
  beta: "beta";
40
42
  live: "live";
@@ -68,6 +70,7 @@ export declare const selfHostModuleV2Schema: z.ZodDiscriminatedUnion<[z.ZodObjec
68
70
  }>;
69
71
  releaseStatus: z.ZodEnum<{
70
72
  planned: "planned";
73
+ alpha: "alpha";
71
74
  testing: "testing";
72
75
  beta: "beta";
73
76
  live: "live";
@@ -122,6 +125,7 @@ export declare const selfHostModuleV2Schema: z.ZodDiscriminatedUnion<[z.ZodObjec
122
125
  }>;
123
126
  releaseStatus: z.ZodEnum<{
124
127
  planned: "planned";
128
+ alpha: "alpha";
125
129
  testing: "testing";
126
130
  beta: "beta";
127
131
  live: "live";
@@ -197,6 +201,7 @@ export declare const selfHostCatalogueSchema: z.ZodDiscriminatedUnion<[z.ZodObje
197
201
  }>;
198
202
  releaseStatus: z.ZodEnum<{
199
203
  planned: "planned";
204
+ alpha: "alpha";
200
205
  testing: "testing";
201
206
  beta: "beta";
202
207
  live: "live";
@@ -257,6 +262,7 @@ export declare const selfHostCatalogueSchema: z.ZodDiscriminatedUnion<[z.ZodObje
257
262
  }>;
258
263
  releaseStatus: z.ZodEnum<{
259
264
  planned: "planned";
265
+ alpha: "alpha";
260
266
  testing: "testing";
261
267
  beta: "beta";
262
268
  live: "live";
@@ -311,6 +317,7 @@ export declare const selfHostCatalogueSchema: z.ZodDiscriminatedUnion<[z.ZodObje
311
317
  }>;
312
318
  releaseStatus: z.ZodEnum<{
313
319
  planned: "planned";
320
+ alpha: "alpha";
314
321
  testing: "testing";
315
322
  beta: "beta";
316
323
  live: "live";
@@ -35,6 +35,7 @@ const moduleDependency = z
35
35
  const availability = z.enum(["planned", "unpublished", "published"]);
36
36
  export const selfHostReleaseStatusSchema = z.enum([
37
37
  "planned",
38
+ "alpha",
38
39
  "testing",
39
40
  "beta",
40
41
  "live",
@@ -118,6 +119,14 @@ export const selfHostModuleSchema = z
118
119
  message: "live modules must have an exact published version",
119
120
  });
120
121
  }
122
+ if (module.releaseStatus === "alpha" &&
123
+ module.availability !== "unpublished") {
124
+ context.addIssue({
125
+ code: "custom",
126
+ path: ["releaseStatus"],
127
+ message: "alpha scaffolds must remain unpublished",
128
+ });
129
+ }
121
130
  if (module.releaseStatus === "planned" &&
122
131
  module.availability !== "planned") {
123
132
  context.addIssue({
@@ -0,0 +1,12 @@
1
+ import { z } from "zod";
2
+ export declare const selfHostEnvironmentBuilderSchema: z.ZodEnum<{
3
+ none: "none";
4
+ windows: "windows";
5
+ powershell: "powershell";
6
+ unix: "unix";
7
+ all: "all";
8
+ }>;
9
+ export type SelfHostEnvironmentBuilder = z.infer<typeof selfHostEnvironmentBuilderSchema>;
10
+ export type SelfHostEnvironmentBuilderFile = "env-builder.mjs" | "env-builder.bat" | "env-builder.ps1" | "env-builder.sh";
11
+ export declare function selfHostEnvironmentBuilderFiles(selection?: SelfHostEnvironmentBuilder): SelfHostEnvironmentBuilderFile[];
12
+ //# sourceMappingURL=environment-builders.d.ts.map
@@ -0,0 +1,25 @@
1
+ import { z } from "zod";
2
+ export const selfHostEnvironmentBuilderSchema = z.enum([
3
+ "none",
4
+ "windows",
5
+ "powershell",
6
+ "unix",
7
+ "all",
8
+ ]);
9
+ export function selfHostEnvironmentBuilderFiles(selection = "none") {
10
+ selfHostEnvironmentBuilderSchema.parse(selection);
11
+ if (selection === "none")
12
+ return [];
13
+ const launchers = {
14
+ windows: "env-builder.bat",
15
+ powershell: "env-builder.ps1",
16
+ unix: "env-builder.sh",
17
+ };
18
+ return [
19
+ "env-builder.mjs",
20
+ ...(selection === "all"
21
+ ? Object.values(launchers)
22
+ : [launchers[selection]]),
23
+ ];
24
+ }
25
+ //# sourceMappingURL=environment-builders.js.map
@@ -1,7 +1,15 @@
1
1
  import { z } from "zod";
2
+ import { type SelfHostEnvironmentBuilder } from "./environment-builders.js";
2
3
  import { type SelfHostCatalogue, type SelfHostDatabaseEngine } from "./catalogue.js";
3
4
  export declare const selfHostBuildManifestSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
4
5
  schemaVersion: z.ZodLiteral<1>;
6
+ environmentBuilder: z.ZodOptional<z.ZodEnum<{
7
+ none: "none";
8
+ windows: "windows";
9
+ powershell: "powershell";
10
+ unix: "unix";
11
+ all: "all";
12
+ }>>;
5
13
  catalogueVersion: z.ZodNumber;
6
14
  core: z.ZodObject<{
7
15
  package: z.ZodString;
@@ -18,6 +26,13 @@ export declare const selfHostBuildManifestSchema: z.ZodDiscriminatedUnion<[z.Zod
18
26
  }, z.core.$strict>>;
19
27
  }, z.core.$strict>, z.ZodObject<{
20
28
  schemaVersion: z.ZodLiteral<2>;
29
+ environmentBuilder: z.ZodOptional<z.ZodEnum<{
30
+ none: "none";
31
+ windows: "windows";
32
+ powershell: "powershell";
33
+ unix: "unix";
34
+ all: "all";
35
+ }>>;
21
36
  databaseEngine: z.ZodOptional<z.ZodEnum<{
22
37
  postgresql: "postgresql";
23
38
  mysql: "mysql";
@@ -52,6 +67,6 @@ export declare const selfHostBuildManifestSchema: z.ZodDiscriminatedUnion<[z.Zod
52
67
  }, z.core.$strict>>;
53
68
  }, z.core.$strict>], "schemaVersion">;
54
69
  export type SelfHostBuildManifest = z.infer<typeof selfHostBuildManifestSchema>;
55
- export declare function createSelfHostBuildManifest(catalogue: SelfHostCatalogue, selectedModuleIds: readonly string[], databaseEngine?: SelfHostDatabaseEngine): SelfHostBuildManifest;
70
+ export declare function createSelfHostBuildManifest(catalogue: SelfHostCatalogue, selectedModuleIds: readonly string[], databaseEngine?: SelfHostDatabaseEngine, environmentBuilder?: SelfHostEnvironmentBuilder): SelfHostBuildManifest;
56
71
  export declare function parseSelfHostBuildManifest(input: unknown, catalogue: SelfHostCatalogue): SelfHostBuildManifest;
57
72
  //# sourceMappingURL=manifest.d.ts.map
@@ -1,6 +1,7 @@
1
1
  import semver from "semver";
2
2
  import { isDeepStrictEqual } from "node:util";
3
3
  import { z } from "zod";
4
+ import { selfHostEnvironmentBuilderSchema, } from "./environment-builders.js";
4
5
  import { isSelfHostModuleCustomerSelectable, selfHostDatabaseEngineSchema, } from "./catalogue.js";
5
6
  const exactVersion = z
6
7
  .string()
@@ -23,6 +24,7 @@ const buildModuleSchema = z
23
24
  const selfHostBuildManifestV1Schema = z
24
25
  .object({
25
26
  schemaVersion: z.literal(1),
27
+ environmentBuilder: selfHostEnvironmentBuilderSchema.optional(),
26
28
  catalogueVersion: z.number().int().positive(),
27
29
  core: buildComponentSchema,
28
30
  generator: buildComponentSchema,
@@ -48,6 +50,7 @@ const buildModuleV2Schema = buildModuleSchema
48
50
  const selfHostBuildManifestV2Schema = z
49
51
  .object({
50
52
  schemaVersion: z.literal(2),
53
+ environmentBuilder: selfHostEnvironmentBuilderSchema.optional(),
51
54
  databaseEngine: selfHostDatabaseEngineSchema.optional(),
52
55
  catalogueVersion: z.number().int().positive(),
53
56
  core: buildComponentSchema,
@@ -82,15 +85,16 @@ export const selfHostBuildManifestSchema = z
82
85
  packages.add(module.package);
83
86
  }
84
87
  });
85
- export function createSelfHostBuildManifest(catalogue, selectedModuleIds, databaseEngine = "postgresql") {
88
+ export function createSelfHostBuildManifest(catalogue, selectedModuleIds, databaseEngine = "postgresql", environmentBuilder = "none") {
86
89
  selfHostDatabaseEngineSchema.parse(databaseEngine);
90
+ selfHostEnvironmentBuilderSchema.parse(environmentBuilder);
87
91
  assertPublishedComponent(catalogue.core, "Helyx runtime");
88
92
  assertPublishedComponent(catalogue.generator, "Helyx generator");
89
93
  if (new Set(selectedModuleIds).size !== selectedModuleIds.length) {
90
94
  throw new Error("Self-host selection contains duplicate module IDs");
91
95
  }
92
96
  if (catalogue.schemaVersion === 2) {
93
- return createSelfHostBuildManifestV2(catalogue, selectedModuleIds, databaseEngine);
97
+ return createSelfHostBuildManifestV2(catalogue, selectedModuleIds, databaseEngine, environmentBuilder);
94
98
  }
95
99
  if (databaseEngine !== "postgresql") {
96
100
  throw new Error("Legacy self-host catalogue supports PostgreSQL only");
@@ -115,6 +119,7 @@ export function createSelfHostBuildManifest(catalogue, selectedModuleIds, databa
115
119
  });
116
120
  return {
117
121
  schemaVersion: 1,
122
+ ...(environmentBuilder !== "none" ? { environmentBuilder } : {}),
118
123
  catalogueVersion: catalogue.catalogueVersion,
119
124
  core: {
120
125
  package: catalogue.core.package,
@@ -127,7 +132,7 @@ export function createSelfHostBuildManifest(catalogue, selectedModuleIds, databa
127
132
  modules,
128
133
  };
129
134
  }
130
- function createSelfHostBuildManifestV2(catalogue, selectedModuleIds, databaseEngine) {
135
+ function createSelfHostBuildManifestV2(catalogue, selectedModuleIds, databaseEngine, environmentBuilder = "none") {
131
136
  const byId = new Map(catalogue.modules.map((module) => [module.id, module]));
132
137
  const explicitlySelected = new Set(selectedModuleIds);
133
138
  const modules = [];
@@ -189,6 +194,7 @@ function createSelfHostBuildManifestV2(catalogue, selectedModuleIds, databaseEng
189
194
  include(id);
190
195
  return {
191
196
  schemaVersion: 2,
197
+ ...(environmentBuilder !== "none" ? { environmentBuilder } : {}),
192
198
  ...(databaseEngine === "mysql" ? { databaseEngine } : {}),
193
199
  catalogueVersion: catalogue.catalogueVersion,
194
200
  core: {
@@ -218,13 +224,20 @@ export function parseSelfHostBuildManifest(input, catalogue) {
218
224
  const selectedModuleIds = manifest.modules
219
225
  .filter(({ moduleKind }) => moduleKind === "customer_feature")
220
226
  .map(({ id }) => id);
221
- const expected = createSelfHostBuildManifestV2(catalogue, selectedModuleIds, manifest.databaseEngine ?? "postgresql");
227
+ const expected = createSelfHostBuildManifestV2(catalogue, selectedModuleIds, manifest.databaseEngine ?? "postgresql", manifest.environmentBuilder ?? "none");
222
228
  if (!isDeepStrictEqual({
223
229
  ...manifest,
230
+ environmentBuilder: manifest.environmentBuilder === "none"
231
+ ? undefined
232
+ : manifest.environmentBuilder,
224
233
  databaseEngine: manifest.databaseEngine === "postgresql"
225
234
  ? undefined
226
235
  : manifest.databaseEngine,
227
- }, { ...expected, databaseEngine: expected.databaseEngine })) {
236
+ }, {
237
+ ...expected,
238
+ databaseEngine: expected.databaseEngine,
239
+ environmentBuilder: expected.environmentBuilder,
240
+ })) {
228
241
  throw new Error("Build manifest modules do not match the trusted catalogue dependency graph");
229
242
  }
230
243
  return expected;
@@ -2,6 +2,7 @@ import { createHash } from "node:crypto";
2
2
  import { spawn } from "node:child_process";
3
3
  import { mkdir, readFile, readdir, rm, stat, writeFile, } from "node:fs/promises";
4
4
  import { dirname, parse, resolve } from "node:path";
5
+ import { selfHostEnvironmentBuilderFiles, } from "./environment-builders.js";
5
6
  import { isSelfHostModuleCustomerSelectable, } from "./catalogue.js";
6
7
  import { parseSelfHostBuildManifest, } from "./manifest.js";
7
8
  import { databaseAdaptersForCatalogue, } from "./database-adapters.js";
@@ -80,6 +81,7 @@ async function writeGeneratedFiles(targetDirectory, manifest, catalogue, databas
80
81
  engines: { node: ">=24 <27", npm: ">=11" },
81
82
  scripts: {
82
83
  setup: "helyx setup",
84
+ envbuilder: "helyx envbuilder",
83
85
  start: "helyx start",
84
86
  doctor: "helyx doctor",
85
87
  migrate: "helyx migrate",
@@ -95,7 +97,10 @@ async function writeGeneratedFiles(targetDirectory, manifest, catalogue, databas
95
97
  };
96
98
  await writeFile(resolve(targetDirectory, "package.json"), formatJson(packageJson), "utf8");
97
99
  await writeFile(resolve(targetDirectory, "helyx.modules.json"), formatJson(moduleCatalogue), "utf8");
98
- for (const fileName of generatedFileNames) {
100
+ for (const fileName of [
101
+ ...generatedFileNames,
102
+ ...selfHostEnvironmentBuilderFiles(manifest.environmentBuilder),
103
+ ]) {
99
104
  const template = await readFile(fileName === "compose.yaml" && databaseEngine === "mysql"
100
105
  ? mysqlComposeTemplateUrl()
101
106
  : templateUrl(fileName), "utf8");
@@ -106,8 +111,13 @@ async function writeGeneratedFiles(targetDirectory, manifest, catalogue, databas
106
111
  : template;
107
112
  if (fileName === ".env.example")
108
113
  validateEnvironmentTemplate(rendered, databaseEngine);
109
- const content = normalizeCrLf(rendered);
110
- await writeFile(resolve(targetDirectory, fileName), content, "utf8");
114
+ const content = fileName.endsWith(".sh")
115
+ ? rendered.replaceAll("\r\n", "\n")
116
+ : normalizeCrLf(rendered);
117
+ await writeFile(resolve(targetDirectory, fileName), content, {
118
+ encoding: "utf8",
119
+ mode: fileName.endsWith(".sh") ? 0o755 : 0o644,
120
+ });
111
121
  }
112
122
  }
113
123
  function renderEnvironmentExample(template, databaseEngine) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@helyx/cli",
3
- "version": "1.4.3",
3
+ "version": "1.6.0",
4
4
  "description": "Command-line tools for running and generating self-hosted Helyx deployments.",
5
5
  "keywords": [
6
6
  "helyx",
@@ -53,15 +53,15 @@
53
53
  },
54
54
  "dependencies": {
55
55
  "@helyx/bot": ">=1.5.2 <2.0.0",
56
- "@helyx/config": ">=1.4.0 <2.0.0",
57
- "@helyx/database": ">=2.4.1 <3.0.0",
56
+ "@helyx/config": ">=1.6.0 <2.0.0",
57
+ "@helyx/database": ">=2.5.0 <3.0.0",
58
58
  "semver": "7.8.5",
59
- "zod": "4.4.3"
59
+ "zod": "4.6.7"
60
60
  },
61
61
  "optionalDependencies": {
62
- "@helyx/database-mysql": ">=0.2.1 <0.3.0"
62
+ "@helyx/database-mysql": ">=0.3.0 <0.4.0"
63
63
  },
64
64
  "devDependencies": {
65
- "@types/semver": "7.7.1"
65
+ "@types/semver": "7.8.0"
66
66
  }
67
67
  }