@memberjunction/cli 2.119.0 → 2.120.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
@@ -209,6 +209,7 @@ Available AI commands:
209
209
  - `actions run` - Execute an AI action with parameters
210
210
  - `prompts list` - List available AI models for direct prompt execution
211
211
  - `prompts run` - Execute a direct prompt with an AI model
212
+ - `audit agent-run` - Audit and analyze AI agent execution runs for debugging
212
213
 
213
214
  **📚 For detailed documentation:** See the [AI-CLI README](../AI/AICLI/README.md)
214
215
 
@@ -248,6 +249,21 @@ mj ai prompts run -p "Explain quantum computing in simple terms"
248
249
  # Use a specific model
249
250
  mj ai prompts run -p "Write a Python function to sort a list" --model "gpt-4"
250
251
 
252
+ # Audit recent agent runs
253
+ mj ai audit agent-run --list --status failed --days 7
254
+
255
+ # Audit specific run with summary
256
+ mj ai audit agent-run <run-id>
257
+
258
+ # Examine specific step in detail
259
+ mj ai audit agent-run <run-id> --step 3 --detail full
260
+
261
+ # Analyze errors in a run
262
+ mj ai audit agent-run <run-id> --errors
263
+
264
+ # Export full audit data
265
+ mj ai audit agent-run <run-id> --export full --file audit.json
266
+
251
267
  # Use system prompt and temperature
252
268
  mj ai prompts run -p "Generate a haiku" --system "You are a poet" --temperature 0.3
253
269
  ```
@@ -281,6 +297,22 @@ mj ai prompts run -p "Generate a haiku" --system "You are a poet" --temperature
281
297
  - `-v, --verbose`: Show detailed execution information
282
298
  - `--timeout <ms>`: Execution timeout in milliseconds (default: 300000)
283
299
 
300
+ **Audit Commands:**
301
+ - `<run-id>`: Agent Run ID (UUID) to audit (optional for --list mode)
302
+ - `-l, --list`: List recent agent runs (filter with other options)
303
+ - `-a, --agent <name>`: Filter by agent name (requires --list)
304
+ - `--status <status>`: Filter by status: success, failed, running, all (default: all)
305
+ - `--days <number>`: Number of days to look back (default: 7)
306
+ - `--limit <number>`: Maximum runs to return (default: 50)
307
+ - `-s, --step <number>`: Show details for specific step (1-based index)
308
+ - `-d, --detail <level>`: Detail level for step: minimal, standard, detailed, full (default: standard)
309
+ - `-e, --errors`: Show only error details and context
310
+ - `--export <type>`: Export data: full, summary, steps
311
+ - `-f, --file <path>`: Output file path for export
312
+ - `--max-tokens <number>`: Max tokens per field (default: 5000, 0 = no limit)
313
+ - `-o, --output <format>`: Output format (compact, json, table, markdown)
314
+ - `-v, --verbose`: Show detailed diagnostic information
315
+
284
316
  #### AI Features:
285
317
 
286
318
  **Progress Tracking**: Real-time visual progress indicators during agent execution
@@ -299,6 +331,15 @@ mj ai prompts run -p "Generate a haiku" --system "You are a poet" --temperature
299
331
  - Natural back-and-forth dialogue
300
332
  - Exit with "exit", "quit", or Ctrl+C
301
333
 
334
+ **Agent Run Auditing**: Comprehensive debugging and analysis tools
335
+ - List recent runs with filtering by agent, status, and date
336
+ - View run summaries with performance metrics and step breakdowns
337
+ - Deep dive into specific steps with smart truncation for large payloads
338
+ - Automatic error pattern detection with suggested fixes
339
+ - Multiple output formats including markdown for AI assistants
340
+ - Export capabilities for offline analysis
341
+ - Optimized for read-only performance with `simple` result type
342
+
302
343
  #### AI Configuration:
303
344
 
304
345
  Add AI-specific settings to your `mj.config.cjs`:
@@ -0,0 +1,24 @@
1
+ import { Command } from '@oclif/core';
2
+ export default class AgentRun extends Command {
3
+ static description: string;
4
+ static examples: string[];
5
+ static flags: {
6
+ output: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
7
+ step: import("@oclif/core/lib/interfaces").OptionFlag<number | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
8
+ detail: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
9
+ errors: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
10
+ list: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
11
+ agent: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
12
+ status: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
13
+ days: import("@oclif/core/lib/interfaces").OptionFlag<number, import("@oclif/core/lib/interfaces").CustomOptions>;
14
+ limit: import("@oclif/core/lib/interfaces").OptionFlag<number, import("@oclif/core/lib/interfaces").CustomOptions>;
15
+ export: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
16
+ file: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
17
+ 'max-tokens': import("@oclif/core/lib/interfaces").OptionFlag<number, import("@oclif/core/lib/interfaces").CustomOptions>;
18
+ verbose: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
19
+ };
20
+ static args: {
21
+ runId: import("@oclif/core/lib/interfaces").Arg<string | undefined, Record<string, unknown>>;
22
+ };
23
+ run(): Promise<void>;
24
+ }
@@ -0,0 +1,213 @@
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
+ var __importDefault = (this && this.__importDefault) || function (mod) {
26
+ return (mod && mod.__esModule) ? mod : { "default": mod };
27
+ };
28
+ Object.defineProperty(exports, "__esModule", { value: true });
29
+ const core_1 = require("@oclif/core");
30
+ const ai_cli_1 = require("@memberjunction/ai-cli");
31
+ const ora_classic_1 = __importDefault(require("ora-classic"));
32
+ const chalk_1 = __importDefault(require("chalk"));
33
+ const fs = __importStar(require("fs/promises"));
34
+ class AgentRun extends core_1.Command {
35
+ static description = 'Audit and analyze AI agent execution runs for debugging and performance analysis';
36
+ static examples = [
37
+ // Summary mode
38
+ '<%= config.bin %> <%= command.id %> abc-123-def-456',
39
+ '<%= config.bin %> <%= command.id %> abc-123-def-456 --output=markdown',
40
+ // Step detail mode
41
+ '<%= config.bin %> <%= command.id %> abc-123-def-456 --step 3',
42
+ '<%= config.bin %> <%= command.id %> abc-123-def-456 --step 3 --detail full',
43
+ // Error analysis
44
+ '<%= config.bin %> <%= command.id %> abc-123-def-456 --errors',
45
+ // List recent runs
46
+ '<%= config.bin %> <%= command.id %> --list --agent "Skip: Requirements Expert"',
47
+ '<%= config.bin %> <%= command.id %> --list --status failed --days 7',
48
+ // Export mode
49
+ '<%= config.bin %> <%= command.id %> abc-123-def-456 --export full --file report.json',
50
+ ];
51
+ static flags = {
52
+ // Output format
53
+ output: core_1.Flags.string({
54
+ char: 'o',
55
+ description: 'Output format',
56
+ options: ['compact', 'json', 'table', 'markdown'],
57
+ default: 'compact',
58
+ }),
59
+ // Step detail mode
60
+ step: core_1.Flags.integer({
61
+ char: 's',
62
+ description: 'Show details for specific step number (1-based index)',
63
+ exclusive: ['list', 'errors'],
64
+ }),
65
+ detail: core_1.Flags.string({
66
+ char: 'd',
67
+ description: 'Detail level for step output (default: standard)',
68
+ options: ['minimal', 'standard', 'detailed', 'full'],
69
+ dependsOn: ['step'],
70
+ }),
71
+ // Error analysis mode
72
+ errors: core_1.Flags.boolean({
73
+ char: 'e',
74
+ description: 'Show only error details and context',
75
+ default: false,
76
+ exclusive: ['step', 'list'],
77
+ }),
78
+ // List mode
79
+ list: core_1.Flags.boolean({
80
+ char: 'l',
81
+ description: 'List recent agent runs',
82
+ default: false,
83
+ exclusive: ['step', 'errors'],
84
+ }),
85
+ agent: core_1.Flags.string({
86
+ char: 'a',
87
+ description: 'Filter by agent name',
88
+ dependsOn: ['list'],
89
+ }),
90
+ status: core_1.Flags.string({
91
+ description: 'Filter by run status',
92
+ options: ['success', 'failed', 'running', 'all'],
93
+ default: 'all',
94
+ dependsOn: ['list'],
95
+ }),
96
+ days: core_1.Flags.integer({
97
+ description: 'Number of days to look back',
98
+ default: 7,
99
+ dependsOn: ['list'],
100
+ }),
101
+ limit: core_1.Flags.integer({
102
+ description: 'Maximum number of runs to return',
103
+ default: 50,
104
+ dependsOn: ['list'],
105
+ }),
106
+ // Export mode
107
+ export: core_1.Flags.string({
108
+ description: 'Export full data to file',
109
+ options: ['full', 'summary', 'steps'],
110
+ dependsOn: ['file'],
111
+ }),
112
+ file: core_1.Flags.string({
113
+ char: 'f',
114
+ description: 'Output file path for export',
115
+ }),
116
+ // Truncation control
117
+ 'max-tokens': core_1.Flags.integer({
118
+ description: 'Maximum tokens per field (0 = no limit)',
119
+ default: 5000,
120
+ }),
121
+ // Verbose mode
122
+ verbose: core_1.Flags.boolean({
123
+ char: 'v',
124
+ description: 'Show detailed diagnostic information',
125
+ default: false,
126
+ }),
127
+ };
128
+ static args = {
129
+ runId: core_1.Args.string({
130
+ description: 'AI Agent Run ID to audit (UUID)',
131
+ required: false, // Optional because --list mode doesn't need it
132
+ }),
133
+ };
134
+ async run() {
135
+ const { args, flags } = await this.parse(AgentRun);
136
+ const spinner = (0, ora_classic_1.default)();
137
+ try {
138
+ const service = new ai_cli_1.AgentAuditService();
139
+ // MODE 1: List recent runs
140
+ if (flags.list) {
141
+ spinner.start('Loading recent agent runs...');
142
+ const runs = await service.listRecentRuns({
143
+ agentName: flags.agent,
144
+ status: flags.status,
145
+ days: flags.days,
146
+ limit: flags.limit,
147
+ });
148
+ spinner.stop();
149
+ this.log(service.formatRunList(runs, flags.output));
150
+ process.exit(0);
151
+ return;
152
+ }
153
+ // Validate runId for non-list modes
154
+ if (!args.runId) {
155
+ this.error('Run ID is required (use --list to see recent runs)');
156
+ }
157
+ // MODE 2: Step detail mode
158
+ if (flags.step != null) {
159
+ spinner.start(`Loading step ${flags.step} details...`);
160
+ const stepDetail = await service.getStepDetail(args.runId, flags.step, {
161
+ detailLevel: (flags.detail || 'standard'),
162
+ maxTokens: flags['max-tokens'],
163
+ });
164
+ spinner.stop();
165
+ this.log(service.formatStepDetail(stepDetail, flags.output));
166
+ process.exit(0);
167
+ return;
168
+ }
169
+ // MODE 3: Error analysis mode
170
+ if (flags.errors) {
171
+ spinner.start('Analyzing errors...');
172
+ const errorAnalysis = await service.analyzeErrors(args.runId);
173
+ spinner.stop();
174
+ this.log(service.formatErrorAnalysis(errorAnalysis, flags.output));
175
+ process.exit(0);
176
+ return;
177
+ }
178
+ // MODE 4: Export mode
179
+ if (flags.export && flags.file) {
180
+ spinner.start('Exporting full audit data...');
181
+ const exportData = await service.exportRun(args.runId, flags.export);
182
+ await fs.writeFile(flags.file, JSON.stringify(exportData, null, 2), 'utf8');
183
+ spinner.stop();
184
+ this.log(chalk_1.default.green(`✓ Full audit data exported to ${flags.file}`));
185
+ this.log(chalk_1.default.dim(` File size: ${(JSON.stringify(exportData).length / 1024).toFixed(1)} KB`));
186
+ process.exit(0);
187
+ return;
188
+ }
189
+ // MODE 5: Summary mode (default)
190
+ spinner.start('Loading agent run summary...');
191
+ const summary = await service.getRunSummary(args.runId, {
192
+ includeStepList: true,
193
+ maxTokens: flags['max-tokens'],
194
+ });
195
+ spinner.stop();
196
+ this.log(service.formatRunSummary(summary, flags.output));
197
+ if (flags.verbose) {
198
+ this.log(chalk_1.default.dim('\n💡 Tip: Use --step <N> to see details for a specific step'));
199
+ this.log(chalk_1.default.dim('💡 Tip: Use --errors to see only error information'));
200
+ }
201
+ process.exit(0);
202
+ }
203
+ catch (error) {
204
+ spinner.fail('Audit failed');
205
+ if (flags.verbose && error instanceof Error) {
206
+ this.log(chalk_1.default.red('\nError Details:'));
207
+ this.log(error.stack || error.message);
208
+ }
209
+ this.error(error);
210
+ }
211
+ }
212
+ }
213
+ exports.default = AgentRun;
@@ -0,0 +1,6 @@
1
+ import { Command } from '@oclif/core';
2
+ export default class Audit extends Command {
3
+ static description: string;
4
+ static hidden: boolean;
5
+ run(): Promise<void>;
6
+ }
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const core_1 = require("@oclif/core");
4
+ class Audit extends core_1.Command {
5
+ static description = 'Analyze and audit AI agent runs, prompts, and actions for debugging and performance analysis';
6
+ static hidden = false;
7
+ async run() {
8
+ // This command just displays help for the audit topic
9
+ await this.config.runCommand('help', ['ai', 'audit']);
10
+ }
11
+ }
12
+ exports.default = Audit;
@@ -1821,6 +1821,222 @@
1821
1821
  "run.js"
1822
1822
  ]
1823
1823
  },
1824
+ "ai:audit:agent-run": {
1825
+ "aliases": [],
1826
+ "args": {
1827
+ "runId": {
1828
+ "description": "AI Agent Run ID to audit (UUID)",
1829
+ "name": "runId",
1830
+ "required": false
1831
+ }
1832
+ },
1833
+ "description": "Audit and analyze AI agent execution runs for debugging and performance analysis",
1834
+ "examples": [
1835
+ "<%= config.bin %> <%= command.id %> abc-123-def-456",
1836
+ "<%= config.bin %> <%= command.id %> abc-123-def-456 --output=markdown",
1837
+ "<%= config.bin %> <%= command.id %> abc-123-def-456 --step 3",
1838
+ "<%= config.bin %> <%= command.id %> abc-123-def-456 --step 3 --detail full",
1839
+ "<%= config.bin %> <%= command.id %> abc-123-def-456 --errors",
1840
+ "<%= config.bin %> <%= command.id %> --list --agent \"Skip: Requirements Expert\"",
1841
+ "<%= config.bin %> <%= command.id %> --list --status failed --days 7",
1842
+ "<%= config.bin %> <%= command.id %> abc-123-def-456 --export full --file report.json"
1843
+ ],
1844
+ "flags": {
1845
+ "output": {
1846
+ "char": "o",
1847
+ "description": "Output format",
1848
+ "name": "output",
1849
+ "default": "compact",
1850
+ "hasDynamicHelp": false,
1851
+ "multiple": false,
1852
+ "options": [
1853
+ "compact",
1854
+ "json",
1855
+ "table",
1856
+ "markdown"
1857
+ ],
1858
+ "type": "option"
1859
+ },
1860
+ "step": {
1861
+ "char": "s",
1862
+ "description": "Show details for specific step number (1-based index)",
1863
+ "exclusive": [
1864
+ "list",
1865
+ "errors"
1866
+ ],
1867
+ "name": "step",
1868
+ "hasDynamicHelp": false,
1869
+ "multiple": false,
1870
+ "type": "option"
1871
+ },
1872
+ "detail": {
1873
+ "char": "d",
1874
+ "dependsOn": [
1875
+ "step"
1876
+ ],
1877
+ "description": "Detail level for step output (default: standard)",
1878
+ "name": "detail",
1879
+ "hasDynamicHelp": false,
1880
+ "multiple": false,
1881
+ "options": [
1882
+ "minimal",
1883
+ "standard",
1884
+ "detailed",
1885
+ "full"
1886
+ ],
1887
+ "type": "option"
1888
+ },
1889
+ "errors": {
1890
+ "char": "e",
1891
+ "description": "Show only error details and context",
1892
+ "exclusive": [
1893
+ "step",
1894
+ "list"
1895
+ ],
1896
+ "name": "errors",
1897
+ "allowNo": false,
1898
+ "type": "boolean"
1899
+ },
1900
+ "list": {
1901
+ "char": "l",
1902
+ "description": "List recent agent runs",
1903
+ "exclusive": [
1904
+ "step",
1905
+ "errors"
1906
+ ],
1907
+ "name": "list",
1908
+ "allowNo": false,
1909
+ "type": "boolean"
1910
+ },
1911
+ "agent": {
1912
+ "char": "a",
1913
+ "dependsOn": [
1914
+ "list"
1915
+ ],
1916
+ "description": "Filter by agent name",
1917
+ "name": "agent",
1918
+ "hasDynamicHelp": false,
1919
+ "multiple": false,
1920
+ "type": "option"
1921
+ },
1922
+ "status": {
1923
+ "dependsOn": [
1924
+ "list"
1925
+ ],
1926
+ "description": "Filter by run status",
1927
+ "name": "status",
1928
+ "default": "all",
1929
+ "hasDynamicHelp": false,
1930
+ "multiple": false,
1931
+ "options": [
1932
+ "success",
1933
+ "failed",
1934
+ "running",
1935
+ "all"
1936
+ ],
1937
+ "type": "option"
1938
+ },
1939
+ "days": {
1940
+ "dependsOn": [
1941
+ "list"
1942
+ ],
1943
+ "description": "Number of days to look back",
1944
+ "name": "days",
1945
+ "default": 7,
1946
+ "hasDynamicHelp": false,
1947
+ "multiple": false,
1948
+ "type": "option"
1949
+ },
1950
+ "limit": {
1951
+ "dependsOn": [
1952
+ "list"
1953
+ ],
1954
+ "description": "Maximum number of runs to return",
1955
+ "name": "limit",
1956
+ "default": 50,
1957
+ "hasDynamicHelp": false,
1958
+ "multiple": false,
1959
+ "type": "option"
1960
+ },
1961
+ "export": {
1962
+ "dependsOn": [
1963
+ "file"
1964
+ ],
1965
+ "description": "Export full data to file",
1966
+ "name": "export",
1967
+ "hasDynamicHelp": false,
1968
+ "multiple": false,
1969
+ "options": [
1970
+ "full",
1971
+ "summary",
1972
+ "steps"
1973
+ ],
1974
+ "type": "option"
1975
+ },
1976
+ "file": {
1977
+ "char": "f",
1978
+ "description": "Output file path for export",
1979
+ "name": "file",
1980
+ "hasDynamicHelp": false,
1981
+ "multiple": false,
1982
+ "type": "option"
1983
+ },
1984
+ "max-tokens": {
1985
+ "description": "Maximum tokens per field (0 = no limit)",
1986
+ "name": "max-tokens",
1987
+ "default": 5000,
1988
+ "hasDynamicHelp": false,
1989
+ "multiple": false,
1990
+ "type": "option"
1991
+ },
1992
+ "verbose": {
1993
+ "char": "v",
1994
+ "description": "Show detailed diagnostic information",
1995
+ "name": "verbose",
1996
+ "allowNo": false,
1997
+ "type": "boolean"
1998
+ }
1999
+ },
2000
+ "hasDynamicHelp": false,
2001
+ "hiddenAliases": [],
2002
+ "id": "ai:audit:agent-run",
2003
+ "pluginAlias": "@memberjunction/cli",
2004
+ "pluginName": "@memberjunction/cli",
2005
+ "pluginType": "core",
2006
+ "strict": true,
2007
+ "enableJsonFlag": false,
2008
+ "isESM": false,
2009
+ "relativePath": [
2010
+ "dist",
2011
+ "commands",
2012
+ "ai",
2013
+ "audit",
2014
+ "agent-run.js"
2015
+ ]
2016
+ },
2017
+ "ai:audit": {
2018
+ "aliases": [],
2019
+ "args": {},
2020
+ "description": "Analyze and audit AI agent runs, prompts, and actions for debugging and performance analysis",
2021
+ "flags": {},
2022
+ "hasDynamicHelp": false,
2023
+ "hidden": false,
2024
+ "hiddenAliases": [],
2025
+ "id": "ai:audit",
2026
+ "pluginAlias": "@memberjunction/cli",
2027
+ "pluginName": "@memberjunction/cli",
2028
+ "pluginType": "core",
2029
+ "strict": true,
2030
+ "enableJsonFlag": false,
2031
+ "isESM": false,
2032
+ "relativePath": [
2033
+ "dist",
2034
+ "commands",
2035
+ "ai",
2036
+ "audit",
2037
+ "index.js"
2038
+ ]
2039
+ },
1824
2040
  "ai:prompts:list": {
1825
2041
  "aliases": [],
1826
2042
  "args": {},
@@ -1961,5 +2177,5 @@
1961
2177
  ]
1962
2178
  }
1963
2179
  },
1964
- "version": "2.119.0"
2180
+ "version": "2.120.0"
1965
2181
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@memberjunction/cli",
3
- "version": "2.119.0",
3
+ "version": "2.120.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.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",
54
+ "@memberjunction/ai-cli": "2.120.0",
55
+ "@memberjunction/codegen-lib": "2.120.0",
56
+ "@memberjunction/core": "2.120.0",
57
+ "@memberjunction/db-auto-doc": "2.120.0",
58
+ "@memberjunction/metadata-sync": "2.120.0",
59
+ "@memberjunction/sqlserver-dataprovider": "2.120.0",
60
+ "@memberjunction/testing-cli": "2.120.0",
61
61
  "@oclif/core": "^3",
62
62
  "@oclif/plugin-help": "^6",
63
63
  "@oclif/plugin-version": "^2.0.17",