@memberjunction/cli 2.118.0 β†’ 2.119.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/README.md CHANGED
@@ -451,6 +451,7 @@ mj dbdoc [COMMAND] [OPTIONS]
451
451
  Available dbdoc commands:
452
452
  - `init` - Initialize a new DBAutoDoc project
453
453
  - `analyze` - Analyze database and generate documentation
454
+ - `generate-queries` - Generate sample SQL queries from existing analysis state
454
455
  - `export` - Export documentation in multiple formats (SQL, Markdown, HTML, CSV, Mermaid)
455
456
  - `status` - Show analysis status and progress
456
457
  - `reset` - Reset analysis state
@@ -472,6 +473,14 @@ mj dbdoc analyze --resume ./output/run-6/state.json
472
473
  # Use custom config
473
474
  mj dbdoc analyze --config ./my-config.json
474
475
 
476
+ # Generate sample SQL queries from existing state
477
+ mj dbdoc generate-queries --from-state ./output/run-1/state.json
478
+
479
+ # Generate with custom settings
480
+ mj dbdoc generate-queries --from-state ./output/run-1/state.json \
481
+ --queries-per-table 10 \
482
+ --output-dir ./queries
483
+
475
484
  # Export all formats
476
485
  mj dbdoc export --sql --markdown --html --csv --mermaid
477
486
 
@@ -504,6 +513,13 @@ mj dbdoc reset --force
504
513
  - `-r, --resume <path>`: Resume from an existing state file
505
514
  - `-c, --config <path>`: Path to config file (default: ./config.json)
506
515
 
516
+ **Generate Queries Command:**
517
+ - `--from-state <path>`: Path to existing state.json file from previous analysis (required)
518
+ - `--output-dir <path>`: Output directory for generated queries (optional)
519
+ - `-c, --config <path>`: Path to config file for database connection and AI settings (default: ./config.json)
520
+ - `--queries-per-table <number>`: Number of queries to generate per table (optional, overrides config)
521
+ - `--max-execution-time <ms>`: Maximum execution time for query validation in milliseconds (optional, overrides config)
522
+
507
523
  **Export Command:**
508
524
  - `-s, --state-file <path>`: Path to state JSON file
509
525
  - `-o, --output-dir <path>`: Output directory for generated files
@@ -541,6 +557,7 @@ mj dbdoc reset --force
541
557
 
542
558
  **Advanced Features:**
543
559
  - πŸ” **Relationship Discovery** - Detect missing primary and foreign keys
560
+ - 🎯 **Sample Query Generation** - Generate reference SQL queries for AI agent training with alignment tracking
544
561
  - πŸ›‘οΈ **Granular Guardrails** - Multi-level resource controls
545
562
  - ⏸️ **Resume Capability** - Pause and resume from checkpoint
546
563
  - πŸ“¦ **Programmatic API** - Use as a library in your applications
@@ -552,6 +569,41 @@ mj dbdoc reset --force
552
569
  - CSV Exports (spreadsheet-ready)
553
570
  - Mermaid Diagrams (standalone ERD files)
554
571
  - Analysis Reports (detailed metrics)
572
+ - Sample Queries (JSON with SQL, metadata, and alignment tracking)
573
+
574
+ **Sample Query Generation:**
575
+
576
+ DBAutoDoc can generate reference SQL queries that solve the **query alignment problem** where multi-query patterns (summary + detail) have inconsistent filtering logic. These "gold standard" queries include:
577
+ - Explicit filtering rules for consistency
578
+ - Alignment tracking via `relatedQueryIds`
579
+ - Query patterns (Summary+Detail, Multi-Entity Drilldown, Time Series)
580
+ - Validated, executable SQL
581
+ - Perfect for few-shot prompting in AI agents like Skip
582
+
583
+ Enable in config:
584
+ ```json
585
+ {
586
+ "analysis": {
587
+ "sampleQueryGeneration": {
588
+ "enabled": true,
589
+ "queriesPerTable": 5,
590
+ "includeMultiQueryPatterns": true,
591
+ "validateAlignment": true
592
+ }
593
+ }
594
+ }
595
+ ```
596
+
597
+ Or generate separately from existing state:
598
+ ```bash
599
+ mj dbdoc generate-queries --from-state ./output/run-1/state.json
600
+ ```
601
+
602
+ **Use Cases:**
603
+ - Training AI agents to generate consistent multi-query patterns
604
+ - Creating reference examples for few-shot prompting
605
+ - Documenting common query patterns for your database
606
+ - Validating that related queries use consistent filtering logic
555
607
 
556
608
  ---
557
609
 
@@ -20,10 +20,8 @@ class Clean extends core_1.Command {
20
20
  async run() {
21
21
  const parsed = await this.parse(Clean);
22
22
  this.flags = parsed.flags;
23
- if (!config_1.config) {
24
- this.error('No configuration found');
25
- }
26
- const flywayConfig = await (0, config_1.getFlywayConfig)(config_1.config);
23
+ const config = (0, config_1.getValidatedConfig)();
24
+ const flywayConfig = await (0, config_1.getFlywayConfig)(config);
27
25
  const flyway = new node_flyway_1.Flyway(flywayConfig);
28
26
  this.log('Resetting MJ database to pre-installation state');
29
27
  this.log('Note that users and roles have not been dropped');
@@ -46,7 +46,7 @@ class DbDocAnalyze extends core_1.Command {
46
46
  async run() {
47
47
  const { flags } = await this.parse(DbDocAnalyze);
48
48
  // Load DBAutoDoc command dynamically
49
- const { default: AnalyzeCommand } = await Promise.resolve().then(() => __importStar(require('@memberjunction/db-auto-doc/dist/commands/analyze.js')));
49
+ const { default: AnalyzeCommand } = await Promise.resolve().then(() => __importStar(require('@memberjunction/db-auto-doc/dist/commands/analyze')));
50
50
  // Build args array for DBAutoDoc command
51
51
  const args = [];
52
52
  if (flags.resume) {
@@ -78,7 +78,7 @@ class DbDocExport extends core_1.Command {
78
78
  async run() {
79
79
  const { flags } = await this.parse(DbDocExport);
80
80
  // Load DBAutoDoc command dynamically
81
- const { default: ExportCommand } = await Promise.resolve().then(() => __importStar(require('@memberjunction/db-auto-doc/dist/commands/export.js')));
81
+ const { default: ExportCommand } = await Promise.resolve().then(() => __importStar(require('@memberjunction/db-auto-doc/dist/commands/export')));
82
82
  // Build args array for DBAutoDoc command
83
83
  const args = [];
84
84
  if (flags['state-file'])
@@ -0,0 +1,13 @@
1
+ import { Command } from '@oclif/core';
2
+ export default class DbDocGenerateQueries extends Command {
3
+ static description: string;
4
+ static examples: string[];
5
+ static flags: {
6
+ 'from-state': import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
7
+ 'output-dir': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
8
+ config: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
9
+ 'queries-per-table': import("@oclif/core/lib/interfaces").OptionFlag<number | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
10
+ 'max-execution-time': import("@oclif/core/lib/interfaces").OptionFlag<number | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
11
+ };
12
+ run(): Promise<void>;
13
+ }
@@ -0,0 +1,82 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ const core_1 = require("@oclif/core");
27
+ class DbDocGenerateQueries extends core_1.Command {
28
+ static description = 'Generate sample SQL queries from existing analysis state (delegates to db-auto-doc generate-queries)';
29
+ static examples = [
30
+ '<%= config.bin %> <%= command.id %> --from-state ./output/run-1/state.json',
31
+ '<%= config.bin %> <%= command.id %> --from-state ./output/run-1/state.json --output-dir ./queries',
32
+ '<%= config.bin %> <%= command.id %> --from-state ./output/run-1/state.json --queries-per-table 10',
33
+ ];
34
+ static flags = {
35
+ 'from-state': core_1.Flags.string({
36
+ description: 'Path to existing state.json file from previous analysis',
37
+ required: true
38
+ }),
39
+ 'output-dir': core_1.Flags.string({
40
+ description: 'Output directory for generated queries',
41
+ required: false
42
+ }),
43
+ config: core_1.Flags.string({
44
+ char: 'c',
45
+ description: 'Path to config file (for database connection and AI settings)',
46
+ default: './config.json'
47
+ }),
48
+ 'queries-per-table': core_1.Flags.integer({
49
+ description: 'Number of queries to generate per table',
50
+ required: false
51
+ }),
52
+ 'max-execution-time': core_1.Flags.integer({
53
+ description: 'Maximum execution time for query validation (ms)',
54
+ required: false
55
+ })
56
+ };
57
+ async run() {
58
+ const { flags } = await this.parse(DbDocGenerateQueries);
59
+ // Load DBAutoDoc command dynamically
60
+ const { default: GenerateQueriesCommand } = await Promise.resolve().then(() => __importStar(require('@memberjunction/db-auto-doc/dist/commands/generate-queries')));
61
+ // Build args array for DBAutoDoc command
62
+ const args = [];
63
+ if (flags['from-state']) {
64
+ args.push('--from-state', flags['from-state']);
65
+ }
66
+ if (flags['output-dir']) {
67
+ args.push('--output-dir', flags['output-dir']);
68
+ }
69
+ if (flags.config) {
70
+ args.push('--config', flags.config);
71
+ }
72
+ if (flags['queries-per-table']) {
73
+ args.push('--queries-per-table', flags['queries-per-table'].toString());
74
+ }
75
+ if (flags['max-execution-time']) {
76
+ args.push('--max-execution-time', flags['max-execution-time'].toString());
77
+ }
78
+ // Execute the DBAutoDoc generate-queries command
79
+ await GenerateQueriesCommand.run(args);
80
+ }
81
+ }
82
+ exports.default = DbDocGenerateQueries;
@@ -31,7 +31,7 @@ class DbDocInit extends core_1.Command {
31
31
  ];
32
32
  async run() {
33
33
  // Load DBAutoDoc command dynamically
34
- const { default: InitCommand } = await Promise.resolve().then(() => __importStar(require('@memberjunction/db-auto-doc/dist/commands/init.js')));
34
+ const { default: InitCommand } = await Promise.resolve().then(() => __importStar(require('@memberjunction/db-auto-doc/dist/commands/init')));
35
35
  // Execute the DBAutoDoc init command
36
36
  await InitCommand.run([]);
37
37
  }
@@ -40,7 +40,7 @@ class DbDocReset extends core_1.Command {
40
40
  async run() {
41
41
  const { flags } = await this.parse(DbDocReset);
42
42
  // Load DBAutoDoc command dynamically
43
- const { default: ResetCommand } = await Promise.resolve().then(() => __importStar(require('@memberjunction/db-auto-doc/dist/commands/reset.js')));
43
+ const { default: ResetCommand } = await Promise.resolve().then(() => __importStar(require('@memberjunction/db-auto-doc/dist/commands/reset')));
44
44
  // Build args array for DBAutoDoc command
45
45
  const args = [];
46
46
  if (flags.force) {
@@ -39,7 +39,7 @@ class DbDocStatus extends core_1.Command {
39
39
  async run() {
40
40
  const { flags } = await this.parse(DbDocStatus);
41
41
  // Load DBAutoDoc command dynamically
42
- const { default: StatusCommand } = await Promise.resolve().then(() => __importStar(require('@memberjunction/db-auto-doc/dist/commands/status.js')));
42
+ const { default: StatusCommand } = await Promise.resolve().then(() => __importStar(require('@memberjunction/db-auto-doc/dist/commands/status')));
43
43
  // Build args array for DBAutoDoc command
44
44
  const args = [];
45
45
  if (flags['state-file']) {
@@ -19,14 +19,12 @@ class Migrate extends core_1.Command {
19
19
  };
20
20
  async run() {
21
21
  const { flags } = await this.parse(Migrate);
22
- if (!config_1.config) {
23
- this.error('No configuration found');
24
- }
25
- const flywayConfig = await (0, config_1.getFlywayConfig)(config_1.config, flags.tag);
22
+ const config = (0, config_1.getValidatedConfig)();
23
+ const flywayConfig = await (0, config_1.getFlywayConfig)(config, flags.tag);
26
24
  const flyway = new node_flyway_1.Flyway(flywayConfig);
27
25
  if (flags.verbose) {
28
26
  this.log(`Connecting to ${flywayConfig.url}`);
29
- this.log(`Migrating ${config_1.config.coreSchema} schema using migrations from:\n\t- ${flywayConfig.migrationLocations.join('\n\t- ')}\n`);
27
+ this.log(`Migrating ${config.coreSchema} schema using migrations from:\n\t- ${flywayConfig.migrationLocations.join('\n\t- ')}\n`);
30
28
  }
31
29
  if (flags.tag) {
32
30
  this.log(`Migrating to ${flags.tag}`);
package/dist/config.d.ts CHANGED
@@ -47,18 +47,22 @@ export declare const config: {
47
47
  coreSchema: string;
48
48
  mjRepoUrl: string;
49
49
  } | undefined;
50
- export declare const updatedConfig: () => {
51
- cleanDisabled: boolean;
52
- dbHost: string;
53
- dbDatabase: string;
54
- dbPort: number;
55
- codeGenLogin: string;
56
- codeGenPassword: string;
57
- migrationsLocation: string;
58
- dbTrustServerCertificate: boolean;
59
- coreSchema: string;
60
- mjRepoUrl: string;
61
- } | undefined;
50
+ /**
51
+ * Get validated config for commands that require database connection.
52
+ * Throws error if config is invalid.
53
+ */
54
+ export declare const getValidatedConfig: () => MJConfig;
55
+ /**
56
+ * Get optional config for commands that don't require database connection.
57
+ * Returns undefined if no config exists, or partial config if it exists.
58
+ */
59
+ export declare const getOptionalConfig: () => Partial<MJConfig> | undefined;
60
+ /**
61
+ * Legacy function for backward compatibility with codegen.
62
+ * Validates and returns updated config.
63
+ * Returns undefined silently if config is invalid (command will handle the error).
64
+ */
65
+ export declare const updatedConfig: () => MJConfig | undefined;
62
66
  export declare const createFlywayUrl: (mjConfig: MJConfig) => string;
63
67
  export declare const getFlywayConfig: (mjConfig: MJConfig, tag?: string) => Promise<FlywayConfig>;
64
68
  export {};
package/dist/config.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getFlywayConfig = exports.createFlywayUrl = exports.updatedConfig = exports.config = void 0;
3
+ exports.getFlywayConfig = exports.createFlywayUrl = exports.updatedConfig = exports.getOptionalConfig = exports.getValidatedConfig = exports.config = void 0;
4
4
  const cosmiconfig_1 = require("cosmiconfig");
5
5
  const node_fs_1 = require("node:fs");
6
6
  const node_os_1 = require("node:os");
@@ -9,6 +9,7 @@ const zod_1 = require("zod");
9
9
  const MJ_REPO_URL = 'https://github.com/MemberJunction/MJ.git';
10
10
  const explorer = (0, cosmiconfig_1.cosmiconfigSync)('mj', { searchStrategy: 'global' });
11
11
  const result = explorer.search(process.cwd());
12
+ // Schema for database-dependent config (required fields)
12
13
  const mjConfigSchema = zod_1.z.object({
13
14
  dbHost: zod_1.z.string().default('localhost'),
14
15
  dbDatabase: zod_1.z.string(),
@@ -21,16 +22,51 @@ const mjConfigSchema = zod_1.z.object({
21
22
  cleanDisabled: zod_1.z.boolean().optional().default(true),
22
23
  mjRepoUrl: zod_1.z.string().url().catch(MJ_REPO_URL),
23
24
  });
24
- const parsedConfig = mjConfigSchema.safeParse(result?.config);
25
- if (!parsedConfig.success) {
26
- console.error('Error parsing config file', JSON.stringify(parsedConfig.error.issues, null, 2));
27
- }
28
- exports.config = parsedConfig.success ? parsedConfig.data : undefined;
25
+ // Schema for non-database commands (all fields optional)
26
+ const mjConfigSchemaOptional = zod_1.z.object({
27
+ dbHost: zod_1.z.string().optional(),
28
+ dbDatabase: zod_1.z.string().optional(),
29
+ dbPort: zod_1.z.number({ coerce: true }).optional(),
30
+ codeGenLogin: zod_1.z.string().optional(),
31
+ codeGenPassword: zod_1.z.string().optional(),
32
+ migrationsLocation: zod_1.z.string().optional().default('filesystem:./migrations'),
33
+ dbTrustServerCertificate: zod_1.z.coerce.boolean().default(false),
34
+ coreSchema: zod_1.z.string().optional().default('__mj'),
35
+ cleanDisabled: zod_1.z.boolean().optional().default(true),
36
+ mjRepoUrl: zod_1.z.string().url().catch(MJ_REPO_URL),
37
+ });
38
+ // Don't validate at module load - let commands decide when they need validated config
39
+ exports.config = result?.config;
40
+ /**
41
+ * Get validated config for commands that require database connection.
42
+ * Throws error if config is invalid.
43
+ */
44
+ const getValidatedConfig = () => {
45
+ const parsedConfig = mjConfigSchema.safeParse(result?.config);
46
+ if (!parsedConfig.success) {
47
+ throw new Error(`Invalid or missing mj.config.cjs file. Database commands require valid configuration.\n` +
48
+ `Missing fields: ${parsedConfig.error.issues.map(i => i.path.join('.')).join(', ')}`);
49
+ }
50
+ return parsedConfig.data;
51
+ };
52
+ exports.getValidatedConfig = getValidatedConfig;
53
+ /**
54
+ * Get optional config for commands that don't require database connection.
55
+ * Returns undefined if no config exists, or partial config if it exists.
56
+ */
57
+ const getOptionalConfig = () => {
58
+ const parsedConfig = mjConfigSchemaOptional.safeParse(result?.config);
59
+ return parsedConfig.success ? parsedConfig.data : undefined;
60
+ };
61
+ exports.getOptionalConfig = getOptionalConfig;
62
+ /**
63
+ * Legacy function for backward compatibility with codegen.
64
+ * Validates and returns updated config.
65
+ * Returns undefined silently if config is invalid (command will handle the error).
66
+ */
29
67
  const updatedConfig = () => {
30
68
  const maybeConfig = mjConfigSchema.safeParse(explorer.search(process.cwd())?.config);
31
- if (!maybeConfig.success) {
32
- console.error('Error parsing config file', JSON.stringify(maybeConfig.error.issues, null, 2));
33
- }
69
+ // Don't log errors here - let the calling command handle validation
34
70
  return maybeConfig.success ? maybeConfig.data : undefined;
35
71
  };
36
72
  exports.updatedConfig = updatedConfig;
@@ -305,6 +305,74 @@
305
305
  "export.js"
306
306
  ]
307
307
  },
308
+ "dbdoc:generate-queries": {
309
+ "aliases": [],
310
+ "args": {},
311
+ "description": "Generate sample SQL queries from existing analysis state (delegates to db-auto-doc generate-queries)",
312
+ "examples": [
313
+ "<%= config.bin %> <%= command.id %> --from-state ./output/run-1/state.json",
314
+ "<%= config.bin %> <%= command.id %> --from-state ./output/run-1/state.json --output-dir ./queries",
315
+ "<%= config.bin %> <%= command.id %> --from-state ./output/run-1/state.json --queries-per-table 10"
316
+ ],
317
+ "flags": {
318
+ "from-state": {
319
+ "description": "Path to existing state.json file from previous analysis",
320
+ "name": "from-state",
321
+ "required": true,
322
+ "hasDynamicHelp": false,
323
+ "multiple": false,
324
+ "type": "option"
325
+ },
326
+ "output-dir": {
327
+ "description": "Output directory for generated queries",
328
+ "name": "output-dir",
329
+ "required": false,
330
+ "hasDynamicHelp": false,
331
+ "multiple": false,
332
+ "type": "option"
333
+ },
334
+ "config": {
335
+ "char": "c",
336
+ "description": "Path to config file (for database connection and AI settings)",
337
+ "name": "config",
338
+ "default": "./config.json",
339
+ "hasDynamicHelp": false,
340
+ "multiple": false,
341
+ "type": "option"
342
+ },
343
+ "queries-per-table": {
344
+ "description": "Number of queries to generate per table",
345
+ "name": "queries-per-table",
346
+ "required": false,
347
+ "hasDynamicHelp": false,
348
+ "multiple": false,
349
+ "type": "option"
350
+ },
351
+ "max-execution-time": {
352
+ "description": "Maximum execution time for query validation (ms)",
353
+ "name": "max-execution-time",
354
+ "required": false,
355
+ "hasDynamicHelp": false,
356
+ "multiple": false,
357
+ "type": "option"
358
+ }
359
+ },
360
+ "hasDynamicHelp": false,
361
+ "hiddenAliases": [],
362
+ "id": "dbdoc:generate-queries",
363
+ "pluginAlias": "@memberjunction/cli",
364
+ "pluginName": "@memberjunction/cli",
365
+ "pluginType": "core",
366
+ "strict": true,
367
+ "enableJsonFlag": false,
368
+ "isESM": false,
369
+ "relativePath": [
370
+ "dist",
371
+ "commands",
372
+ "dbdoc",
373
+ "generate-queries.js"
374
+ ]
375
+ },
308
376
  "dbdoc": {
309
377
  "aliases": [],
310
378
  "args": {},
@@ -1893,5 +1961,5 @@
1893
1961
  ]
1894
1962
  }
1895
1963
  },
1896
- "version": "2.118.0"
1964
+ "version": "2.119.0"
1897
1965
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@memberjunction/cli",
3
- "version": "2.118.0",
3
+ "version": "2.119.0",
4
4
  "description": "MemberJunction command line tools",
5
5
  "keywords": [
6
6
  "oclif"
@@ -51,13 +51,13 @@
51
51
  },
52
52
  "dependencies": {
53
53
  "@inquirer/prompts": "^5.0.1",
54
- "@memberjunction/ai-cli": "2.118.0",
55
- "@memberjunction/codegen-lib": "2.118.0",
56
- "@memberjunction/core": "2.118.0",
57
- "@memberjunction/db-auto-doc": "2.118.0",
58
- "@memberjunction/metadata-sync": "2.118.0",
59
- "@memberjunction/sqlserver-dataprovider": "2.118.0",
60
- "@memberjunction/testing-cli": "2.118.0",
54
+ "@memberjunction/ai-cli": "2.119.0",
55
+ "@memberjunction/codegen-lib": "2.119.0",
56
+ "@memberjunction/core": "2.119.0",
57
+ "@memberjunction/db-auto-doc": "2.119.0",
58
+ "@memberjunction/metadata-sync": "2.119.0",
59
+ "@memberjunction/sqlserver-dataprovider": "2.119.0",
60
+ "@memberjunction/testing-cli": "2.119.0",
61
61
  "@oclif/core": "^3",
62
62
  "@oclif/plugin-help": "^6",
63
63
  "@oclif/plugin-version": "^2.0.17",