genlayer 0.20.0 → 0.21.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/.env.example CHANGED
@@ -20,10 +20,8 @@ JSONRPC_REPLICAS='1' # number of JsonRPC container replicas to run, used
20
20
 
21
21
 
22
22
  # WebRequest Server Configuration
23
- WEBREQUESTPORT=5000
24
- WEBREQUESTSELENIUMPORT=5001
25
- WEBREQUESTPROTOCOL='http'
26
- WEBREQUESTHOST='webrequest'
23
+ WEBDRIVERHOST=webdriver
24
+ WEBDRIVERPORT=4444
27
25
 
28
26
 
29
27
  # Ollama server details
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.21.0 (2025-07-14)
4
+
5
+ ### Features
6
+
7
+ * update docker compose ([#237](https://github.com/yeagerai/genlayer-cli/issues/237)) ([18ea508](https://github.com/yeagerai/genlayer-cli/commit/18ea508a155bc9112612430add49c4c0e23ad3d5))
8
+
3
9
  ## 0.20.0 (2025-07-09)
4
10
 
5
11
  ### Features
package/dist/index.js CHANGED
@@ -17723,7 +17723,7 @@ var require_semver2 = __commonJS({
17723
17723
  import { program } from "commander";
17724
17724
 
17725
17725
  // package.json
17726
- var version = "0.20.0";
17726
+ var version = "0.21.0";
17727
17727
  var package_default = {
17728
17728
  name: "genlayer",
17729
17729
  version,
@@ -17814,7 +17814,7 @@ var CLI_DESCRIPTION = "GenLayer CLI is a development environment for the GenLaye
17814
17814
  import inquirer2 from "inquirer";
17815
17815
 
17816
17816
  // src/lib/config/simulator.ts
17817
- var localnetCompatibleVersion = "v0.55.0";
17817
+ var localnetCompatibleVersion = "v0.65.0";
17818
17818
  var DEFAULT_JSON_RPC_URL = "http://localhost:4000/api";
17819
17819
  var CONTAINERS_NAME_PREFIX = "/genlayer-";
17820
17820
  var IMAGES_NAME_PREFIX = "yeagerai";
@@ -41882,6 +41882,19 @@ Run npm install -g genlayer to update
41882
41882
  }
41883
41883
  return version5;
41884
41884
  }
41885
+ compareVersions(version1, version22) {
41886
+ const v1 = version1.replace(/^v/, "");
41887
+ const v2 = version22.replace(/^v/, "");
41888
+ const parts1 = v1.split("-")[0].split(".").map(Number);
41889
+ const parts2 = v2.split("-")[0].split(".").map(Number);
41890
+ for (let i2 = 0; i2 < Math.max(parts1.length, parts2.length); i2++) {
41891
+ const part1 = parts1[i2] || 0;
41892
+ const part2 = parts2[i2] || 0;
41893
+ if (part1 < part2) return -1;
41894
+ if (part1 > part2) return 1;
41895
+ }
41896
+ return 0;
41897
+ }
41885
41898
  async isLocalnetRunning() {
41886
41899
  const genlayerContainers = await this.getGenlayerContainers();
41887
41900
  const runningContainers = genlayerContainers.filter((container) => container.State === "running");
@@ -41925,6 +41938,10 @@ var InitAction = class extends BaseAction {
41925
41938
  let localnetVersion = options.localnetVersion;
41926
41939
  if (localnetVersion !== "latest") {
41927
41940
  localnetVersion = this.simulatorService.normalizeLocalnetVersion(localnetVersion);
41941
+ if (this.simulatorService.compareVersions(localnetVersion, localnetCompatibleVersion) < 0) {
41942
+ this.failSpinner(`Localnet version ${localnetVersion} is not supported. Minimum required version is ${localnetCompatibleVersion}. Please use a newer version.`);
41943
+ return;
41944
+ }
41928
41945
  }
41929
41946
  this.startSpinner("Checking CLI version...");
41930
41947
  await this.simulatorService.checkCliVersion();
@@ -42139,7 +42156,7 @@ var StopAction = class extends BaseAction {
42139
42156
 
42140
42157
  // src/commands/general/index.ts
42141
42158
  function initializeGeneralCommands(program2) {
42142
- program2.command("init").description("Initialize the GenLayer Environment").option("--numValidators <numValidators>", "Number of validators", "5").option("--headless", "Headless mode", false).option("--reset-db", "Reset Database", false).option("--localnet-version <localnetVersion>", "Select a specific localnet version", localnetCompatibleVersion).option("--ollama", "Enable Ollama container", false).action(async (options) => {
42159
+ program2.command("init").description("Initialize the GenLayer Environment").option("--numValidators <numValidators>", "Number of validators", "5").option("--headless", "Headless mode", false).option("--reset-db", "Reset Database", false).option("--localnet-version <localnetVersion>", `Select a specific localnet version (minimum: ${localnetCompatibleVersion})`, localnetCompatibleVersion).option("--ollama", "Enable Ollama container", false).action(async (options) => {
42143
42160
  const initAction = new InitAction();
42144
42161
  await initAction.execute(options);
42145
42162
  });
@@ -32,9 +32,8 @@ services:
32
32
  - FLASK_SERVER_PORT=${RPCPORT:-5000}
33
33
  - PYTHONUNBUFFERED=1
34
34
  - RPCDEBUGPORT=${RPCDEBUGPORT:-5001}
35
- - WEBREQUESTPORT=${WEBREQUESTPORT:-5002}
36
- - WEBREQUESTHOST=${WEBREQUESTHOST:-localhost}
37
- - WEBREQUESTPROTOCOL=${WEBREQUESTPROTOCOL:-http}
35
+ - WEBDRIVERHOST=${WEBDRIVERHOST:-webdriver}
36
+ - WEBDRIVERPORT=${WEBDRIVERPORT:-4444}
38
37
  ports:
39
38
  - "${RPCPORT:-5000}:${RPCPORT:-5000}"
40
39
  - "${RPCDEBUGPORT:-5001}:${RPCDEBUGPORT:-5001}"
@@ -49,8 +48,8 @@ services:
49
48
  depends_on:
50
49
  database-migration:
51
50
  condition: service_completed_successfully
52
- webrequest:
53
- condition: service_healthy
51
+ webdriver:
52
+ condition: service_healthy
54
53
  expose:
55
54
  - "${RPCPORT:-5000}"
56
55
  restart: always
@@ -67,25 +66,14 @@ services:
67
66
  - hardhat_artifacts:/app/hardhat/artifacts
68
67
  - hardhat_deployments:/app/hardhat/deployments
69
68
 
70
- webrequest:
71
- image: yeagerai/simulator-webrequest:${LOCALNETVERSION:-latest}
69
+
70
+ webdriver:
71
+ image: yeagerai/genlayer-genvm-webdriver:0.0.3
72
72
  shm_size: 2gb
73
73
  environment:
74
- - FLASK_SERVER_PORT=${WEBREQUESTPORT:-5002}
75
- - WEBREQUESTSELENIUMPORT=${WEBREQUESTSELENIUMPORT:-4444}
76
- - PYTHONUNBUFFERED=1
77
- - WEBREQUESTPORT=${WEBREQUESTPORT}
78
- - WEBREQUESTHOST=${WEBREQUESTHOST}
79
- - WEBREQUESTPROTOCOL=${WEBREQUESTPROTOCOL}
74
+ - PORT=${WEBDRIVERPORT:-4444}
80
75
  expose:
81
- - "${WEBREQUESTPORT:-5002}:${WEBREQUESTPORT:-5002}"
82
- - "${WEBREQUESTSELENIUMPORT:-4444}:${WEBREQUESTSELENIUMPORT:-4444}"
83
- env_file:
84
- - ./.env
85
- depends_on:
86
- ollama:
87
- condition: service_started
88
- required: false
76
+ - "${WEBDRIVERPORT:-4444}"
89
77
  restart: always
90
78
  security_opt:
91
79
  - "no-new-privileges=true"
@@ -94,7 +82,7 @@ services:
94
82
  options:
95
83
  max-size: "10m"
96
84
  max-file: "3"
97
-
85
+
98
86
  ollama:
99
87
  image: ollama/ollama:0.6.6
100
88
  ports:
@@ -142,14 +130,9 @@ services:
142
130
  image: yeagerai/simulator-database-migration:${LOCALNETVERSION:-latest}
143
131
  environment:
144
132
  - DB_URL=postgresql://${DBUSER:-postgres}:${DBPASSWORD:-postgres}@postgres/${DBNAME:-simulator_db}
145
- - WEBREQUESTPORT=${WEBREQUESTPORT:-5002}
146
- - WEBREQUESTHOST=${WEBREQUESTHOST:-localhost}
147
- - WEBREQUESTPROTOCOL=${WEBREQUESTPROTOCOL:-http}
148
133
  depends_on:
149
134
  postgres:
150
135
  condition: service_healthy
151
- webrequest:
152
- condition: service_healthy
153
136
 
154
137
  hardhat:
155
138
  image: yeagerai/simulator-hardhat:${LOCALNETVERSION:-latest}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "genlayer",
3
- "version": "0.20.0",
3
+ "version": "0.21.0",
4
4
  "description": "GenLayer Command Line Tool",
5
5
  "main": "src/index.ts",
6
6
  "type": "module",
@@ -13,7 +13,7 @@ export function initializeGeneralCommands(program: Command) {
13
13
  .option("--numValidators <numValidators>", "Number of validators", "5")
14
14
  .option("--headless", "Headless mode", false)
15
15
  .option("--reset-db", "Reset Database", false)
16
- .option("--localnet-version <localnetVersion>", "Select a specific localnet version", localnetCompatibleVersion)
16
+ .option("--localnet-version <localnetVersion>", `Select a specific localnet version (minimum: ${localnetCompatibleVersion})`, localnetCompatibleVersion)
17
17
  .option("--ollama", "Enable Ollama container", false)
18
18
  .action(async (options: InitActionOptions) => {
19
19
  const initAction = new InitAction();
@@ -1,7 +1,7 @@
1
1
  import inquirer from "inquirer";
2
2
  import {DistinctQuestion} from "inquirer";
3
3
  import {ISimulatorService} from "../../lib/interfaces/ISimulatorService";
4
- import {AI_PROVIDERS_CONFIG, AiProviders} from "../../lib/config/simulator";
4
+ import {AI_PROVIDERS_CONFIG, AiProviders, localnetCompatibleVersion} from "../../lib/config/simulator";
5
5
  import {OllamaAction} from "../update/ollama";
6
6
  import {BaseAction} from "../../lib/actions/BaseAction";
7
7
  import {SimulatorService} from "../../lib/services/simulator";
@@ -46,6 +46,11 @@ export class InitAction extends BaseAction {
46
46
  let localnetVersion = options.localnetVersion;
47
47
  if (localnetVersion !== "latest") {
48
48
  localnetVersion = this.simulatorService.normalizeLocalnetVersion(localnetVersion);
49
+
50
+ if (this.simulatorService.compareVersions(localnetVersion, localnetCompatibleVersion) < 0) {
51
+ this.failSpinner(`Localnet version ${localnetVersion} is not supported. Minimum required version is ${localnetCompatibleVersion}. Please use a newer version.`);
52
+ return;
53
+ }
49
54
  }
50
55
 
51
56
  this.startSpinner("Checking CLI version...");
@@ -1,4 +1,4 @@
1
- export const localnetCompatibleVersion = "v0.55.0";
1
+ export const localnetCompatibleVersion = "v0.65.0";
2
2
  export const DEFAULT_JSON_RPC_URL = "http://localhost:4000/api";
3
3
  export const CONTAINERS_NAME_PREFIX = "/genlayer-";
4
4
  export const IMAGES_NAME_PREFIX = "yeagerai";
@@ -19,6 +19,7 @@ export interface ISimulatorService {
19
19
  cleanDatabase(): Promise<boolean>;
20
20
  addConfigToEnvFile(newConfig: Record<string, string>): void;
21
21
  normalizeLocalnetVersion(version: string): string;
22
+ compareVersions(version1: string, version2: string): number;
22
23
  isLocalnetRunning(): Promise<boolean>;
23
24
  }
24
25
 
@@ -305,6 +305,24 @@ export class SimulatorService implements ISimulatorService {
305
305
  return version
306
306
  }
307
307
 
308
+ public compareVersions(version1: string, version2: string): number {
309
+ const v1 = version1.replace(/^v/, '');
310
+ const v2 = version2.replace(/^v/, '');
311
+
312
+ const parts1 = v1.split('-')[0].split('.').map(Number);
313
+ const parts2 = v2.split('-')[0].split('.').map(Number);
314
+
315
+ for (let i = 0; i < Math.max(parts1.length, parts2.length); i++) {
316
+ const part1 = parts1[i] || 0;
317
+ const part2 = parts2[i] || 0;
318
+
319
+ if (part1 < part2) return -1;
320
+ if (part1 > part2) return 1;
321
+ }
322
+
323
+ return 0;
324
+ }
325
+
308
326
  public async isLocalnetRunning(): Promise<boolean> {
309
327
  const genlayerContainers = await this.getGenlayerContainers();
310
328
  const runningContainers = genlayerContainers.filter(container => container.State === "running");
@@ -3,6 +3,7 @@ import inquirer from "inquirer";
3
3
  import {InitAction, InitActionOptions} from "../../src/commands/general/init";
4
4
  import {SimulatorService} from "../../src/lib/services/simulator";
5
5
  import {OllamaAction} from "../../src/commands/update/ollama";
6
+ import {localnetCompatibleVersion} from "../../src/lib/config/simulator";
6
7
 
7
8
  describe("InitAction", () => {
8
9
  let initAction: InitAction;
@@ -28,7 +29,7 @@ describe("InitAction", () => {
28
29
  numValidators: 5,
29
30
  headless: false,
30
31
  resetDb: false,
31
- localnetVersion: "v1.0.0",
32
+ localnetVersion: localnetCompatibleVersion,
32
33
  ollama: false
33
34
  };
34
35
 
@@ -133,7 +134,7 @@ describe("InitAction", () => {
133
134
  OPENAIKEY: "API_KEY_OPENAI",
134
135
  HEURISTAIAPIKEY: "API_KEY_HEURIST",
135
136
  });
136
- expect(addConfigToEnvFileSpy).toHaveBeenCalledWith({LOCALNETVERSION: "v1.0.0"});
137
+ expect(addConfigToEnvFileSpy).toHaveBeenCalledWith({LOCALNETVERSION: localnetCompatibleVersion});
137
138
  expect(runSimulatorSpy).toHaveBeenCalled();
138
139
  expect(waitForSimulatorSpy).toHaveBeenCalled();
139
140
  expect(deleteAllValidatorsSpy).toHaveBeenCalled();
@@ -155,7 +156,7 @@ describe("InitAction", () => {
155
156
  numValidators: 5,
156
157
  headless: true,
157
158
  resetDb: true,
158
- localnetVersion: "v1.0.0",
159
+ localnetVersion: localnetCompatibleVersion,
159
160
  ollama: true
160
161
  };
161
162
  await initAction.execute(headlessOptions);
@@ -168,7 +169,7 @@ describe("InitAction", () => {
168
169
  });
169
170
 
170
171
  test("normalizes localnetVersion if not 'latest'", async () => {
171
- const customVersion = "custom-v1";
172
+ const customVersion = "v99";
172
173
  normalizeLocalnetVersionSpy.mockReturnValue(customVersion);
173
174
  inquirerPromptSpy
174
175
  .mockResolvedValueOnce({confirmAction: true})
@@ -255,6 +256,49 @@ describe("InitAction", () => {
255
256
  );
256
257
  });
257
258
 
259
+ test("fails if localnet version is older than compatible version", async () => {
260
+ const olderVersion = "v0.0.1";
261
+ normalizeLocalnetVersionSpy.mockReturnValue(olderVersion);
262
+ await initAction.execute({...defaultOptions, localnetVersion: olderVersion});
263
+ expect((initAction as any).failSpinner).toHaveBeenCalledWith(
264
+ `Localnet version ${olderVersion} is not supported. Minimum required version is ${localnetCompatibleVersion}. Please use a newer version.`
265
+ );
266
+ });
267
+
268
+ test("should proceed when localnet version is equal to compatible version", async () => {
269
+ normalizeLocalnetVersionSpy.mockReturnValue(localnetCompatibleVersion);
270
+ inquirerPromptSpy
271
+ .mockResolvedValueOnce({selectedLlmProviders: ["openai"]})
272
+ .mockResolvedValueOnce({openai: "API_KEY_OPENAI"});
273
+ await initAction.execute({...defaultOptions, localnetVersion: localnetCompatibleVersion});
274
+ expect((initAction as any).failSpinner).not.toHaveBeenCalledWith(
275
+ expect.stringContaining("Localnet version")
276
+ );
277
+ });
278
+
279
+ test("should proceed when localnet version is newer than compatible version", async () => {
280
+ const newerVersion = "v99.99.99";
281
+ normalizeLocalnetVersionSpy.mockReturnValue(newerVersion);
282
+ inquirerPromptSpy
283
+ .mockResolvedValueOnce({selectedLlmProviders: ["openai"]})
284
+ .mockResolvedValueOnce({openai: "API_KEY_OPENAI"});
285
+ await initAction.execute({...defaultOptions, localnetVersion: newerVersion});
286
+ expect((initAction as any).failSpinner).not.toHaveBeenCalledWith(
287
+ expect.stringContaining("Localnet version")
288
+ );
289
+ });
290
+
291
+ test("should skip version validation when localnet version is 'latest'", async () => {
292
+ inquirerPromptSpy
293
+ .mockResolvedValueOnce({selectedLlmProviders: ["openai"]})
294
+ .mockResolvedValueOnce({openai: "API_KEY_OPENAI"});
295
+ await initAction.execute({...defaultOptions, localnetVersion: "latest"});
296
+ expect(normalizeLocalnetVersionSpy).not.toHaveBeenCalled();
297
+ expect((initAction as any).failSpinner).not.toHaveBeenCalledWith(
298
+ expect.stringContaining("Localnet version")
299
+ );
300
+ });
301
+
258
302
  test("fails if checkInstallRequirements throws an error", async () => {
259
303
  const error = new Error("Install error");
260
304
  checkInstallRequirementsSpy.mockRejectedValue(error);
@@ -83,6 +83,16 @@ describe("init command", () => {
83
83
  expect(openFrontendSpy).not.toHaveBeenCalled();
84
84
  });
85
85
 
86
+ test("option --localnet-version description includes minimum version", async () => {
87
+ const localnetVersionOption = getCommandOption(initCommand, "--localnet-version");
88
+ expect(localnetVersionOption?.description).toBe(`Select a specific localnet version (minimum: ${localnetCompatibleVersion})`);
89
+ });
90
+
91
+ test("option --localnet-version default value is compatible version", async () => {
92
+ const localnetVersionOption = getCommandOption(initCommand, "--localnet-version");
93
+ expect(localnetVersionOption?.defaultValue).toBe(localnetCompatibleVersion);
94
+ });
95
+
86
96
  test("option --ollama is accepted", async () => {
87
97
  program.parse(["node", "test", "init", "--ollama"]);
88
98
  expect(InitAction).toHaveBeenCalledTimes(1);
@@ -603,3 +603,63 @@ describe("normalizeLocalnetVersion", () => {
603
603
  expect(console.error).toHaveBeenCalledWith(mockError);
604
604
  });
605
605
  });
606
+
607
+ describe("compareVersions", () => {
608
+ test("should return 0 when versions are equal", () => {
609
+ expect(simulatorService.compareVersions("v1.0.0", "v1.0.0")).toBe(0);
610
+ expect(simulatorService.compareVersions("1.0.0", "v1.0.0")).toBe(0);
611
+ expect(simulatorService.compareVersions("v1.0.0", "1.0.0")).toBe(0);
612
+ expect(simulatorService.compareVersions("1.0.0", "1.0.0")).toBe(0);
613
+ });
614
+
615
+ test("should return -1 when first version is less than second", () => {
616
+ expect(simulatorService.compareVersions("v0.64.0", "v0.65.0")).toBe(-1);
617
+ expect(simulatorService.compareVersions("v0.65.0", "v0.66.0")).toBe(-1);
618
+ expect(simulatorService.compareVersions("v0.64.9", "v0.65.0")).toBe(-1);
619
+ expect(simulatorService.compareVersions("v1.0.0", "v2.0.0")).toBe(-1);
620
+ expect(simulatorService.compareVersions("v1.0.0", "v1.1.0")).toBe(-1);
621
+ expect(simulatorService.compareVersions("v1.0.0", "v1.0.1")).toBe(-1);
622
+ });
623
+
624
+ test("should return 1 when first version is greater than second", () => {
625
+ expect(simulatorService.compareVersions("v0.66.0", "v0.65.0")).toBe(1);
626
+ expect(simulatorService.compareVersions("v0.65.1", "v0.65.0")).toBe(1);
627
+ expect(simulatorService.compareVersions("v2.0.0", "v1.0.0")).toBe(1);
628
+ expect(simulatorService.compareVersions("v1.1.0", "v1.0.0")).toBe(1);
629
+ expect(simulatorService.compareVersions("v1.0.1", "v1.0.0")).toBe(1);
630
+ });
631
+
632
+ test("should handle versions with different number of parts", () => {
633
+ expect(simulatorService.compareVersions("v1.0", "v1.0.0")).toBe(0);
634
+ expect(simulatorService.compareVersions("v1.0.0", "v1.0")).toBe(0);
635
+ expect(simulatorService.compareVersions("v1.0", "v1.0.1")).toBe(-1);
636
+ expect(simulatorService.compareVersions("v1.0.1", "v1.0")).toBe(1);
637
+ });
638
+
639
+ test("should handle versions without 'v' prefix", () => {
640
+ expect(simulatorService.compareVersions("1.0.0", "1.0.0")).toBe(0);
641
+ expect(simulatorService.compareVersions("1.0.0", "1.0.1")).toBe(-1);
642
+ expect(simulatorService.compareVersions("1.0.1", "1.0.0")).toBe(1);
643
+ });
644
+
645
+ test("should handle mixed prefix versions", () => {
646
+ expect(simulatorService.compareVersions("v1.0.0", "1.0.0")).toBe(0);
647
+ expect(simulatorService.compareVersions("1.0.0", "v1.0.1")).toBe(-1);
648
+ expect(simulatorService.compareVersions("v1.0.1", "1.0.0")).toBe(1);
649
+ });
650
+
651
+ test("should handle pre-release versions by comparing base version", () => {
652
+ expect(simulatorService.compareVersions("v1.0.0-alpha", "v1.0.0")).toBe(0);
653
+ expect(simulatorService.compareVersions("v1.0.0-beta", "v1.0.0-alpha")).toBe(0);
654
+ expect(simulatorService.compareVersions("v1.0.0-alpha", "v1.0.1")).toBe(-1);
655
+ expect(simulatorService.compareVersions("v1.0.1-beta", "v1.0.0")).toBe(1);
656
+ expect(simulatorService.compareVersions("v1.0.0-test000", "v1.0.0-beta")).toBe(0);
657
+ });
658
+
659
+ test("should handle mixed pre-release and regular versions", () => {
660
+ expect(simulatorService.compareVersions("1.0.0-alpha", "v1.0.0")).toBe(0);
661
+ expect(simulatorService.compareVersions("v1.0.0", "1.0.0-beta")).toBe(0);
662
+ expect(simulatorService.compareVersions("1.0.0-alpha", "v1.0.1")).toBe(-1);
663
+ expect(simulatorService.compareVersions("v1.0.1-beta", "1.0.0")).toBe(1);
664
+ });
665
+ });