@lexq/cli 0.1.12 → 0.1.14

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/dist/index.js CHANGED
@@ -75,7 +75,7 @@ async function apiRequest(method, path, options = {}) {
75
75
  }
76
76
  const headers = {
77
77
  "X-API-KEY": apiKey,
78
- "Accept": "application/json"
78
+ Accept: "application/json"
79
79
  };
80
80
  if (options.body) {
81
81
  headers["Content-Type"] = "application/json";
@@ -194,11 +194,10 @@ function registerAuthCommands(program) {
194
194
  console.error('Not authenticated. Run "lexq auth login" first.');
195
195
  process.exit(1);
196
196
  }
197
- const info = await apiRequest(
198
- "GET",
199
- "whoami",
200
- { apiKey: config.apiKey, baseUrl: config.baseUrl }
201
- );
197
+ const info = await apiRequest("GET", "whoami", {
198
+ apiKey: config.apiKey,
199
+ baseUrl: config.baseUrl
200
+ });
202
201
  const masked = config.apiKey.length > 8 ? config.apiKey.substring(0, 4) + "****" + config.apiKey.substring(config.apiKey.length - 4) : "****";
203
202
  printJson({
204
203
  ...info,
@@ -244,17 +243,13 @@ function registerGroupCommands(program) {
244
243
  try {
245
244
  const globalOpts = program.opts();
246
245
  const format = globalOpts.format ?? "json";
247
- const data = await apiRequest(
248
- "GET",
249
- "policy-groups",
250
- {
251
- apiKey: globalOpts.apiKey,
252
- baseUrl: globalOpts.baseUrl,
253
- dryRun: globalOpts.dryRun,
254
- verbose: globalOpts.verbose,
255
- params: { page: opts.page, size: opts.size }
256
- }
257
- );
246
+ const data = await apiRequest("GET", "policy-groups", {
247
+ apiKey: globalOpts.apiKey,
248
+ baseUrl: globalOpts.baseUrl,
249
+ dryRun: globalOpts.dryRun,
250
+ verbose: globalOpts.verbose,
251
+ params: { page: opts.page, size: opts.size }
252
+ });
258
253
  if (format === "table") {
259
254
  printTable(
260
255
  ["ID", "Name", "Status", "Priority", "Version", "Updated"],
@@ -281,16 +276,12 @@ ${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
281
276
  groups.command("get").description("Get a policy group by ID").requiredOption("--id <groupId>", "Policy group ID").action(async (opts) => {
282
277
  try {
283
278
  const globalOpts = program.opts();
284
- const data = await apiRequest(
285
- "GET",
286
- `policy-groups/${opts.id}`,
287
- {
288
- apiKey: globalOpts.apiKey,
289
- baseUrl: globalOpts.baseUrl,
290
- dryRun: globalOpts.dryRun,
291
- verbose: globalOpts.verbose
292
- }
293
- );
279
+ const data = await apiRequest("GET", `policy-groups/${opts.id}`, {
280
+ apiKey: globalOpts.apiKey,
281
+ baseUrl: globalOpts.baseUrl,
282
+ dryRun: globalOpts.dryRun,
283
+ verbose: globalOpts.verbose
284
+ });
294
285
  printJson(data);
295
286
  } catch (error) {
296
287
  printError(error);
@@ -301,17 +292,13 @@ ${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
301
292
  try {
302
293
  const globalOpts = program.opts();
303
294
  const body = JSON.parse(opts.json);
304
- const data = await apiRequest(
305
- "POST",
306
- "policy-groups",
307
- {
308
- apiKey: globalOpts.apiKey,
309
- baseUrl: globalOpts.baseUrl,
310
- dryRun: globalOpts.dryRun,
311
- verbose: globalOpts.verbose,
312
- body
313
- }
314
- );
295
+ const data = await apiRequest("POST", "policy-groups", {
296
+ apiKey: globalOpts.apiKey,
297
+ baseUrl: globalOpts.baseUrl,
298
+ dryRun: globalOpts.dryRun,
299
+ verbose: globalOpts.verbose,
300
+ body
301
+ });
315
302
  printJson(data);
316
303
  } catch (error) {
317
304
  printError(error);
@@ -322,17 +309,13 @@ ${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
322
309
  try {
323
310
  const globalOpts = program.opts();
324
311
  const body = JSON.parse(opts.json);
325
- const data = await apiRequest(
326
- "PUT",
327
- `policy-groups/${opts.id}`,
328
- {
329
- apiKey: globalOpts.apiKey,
330
- baseUrl: globalOpts.baseUrl,
331
- dryRun: globalOpts.dryRun,
332
- verbose: globalOpts.verbose,
333
- body
334
- }
335
- );
312
+ const data = await apiRequest("PUT", `policy-groups/${opts.id}`, {
313
+ apiKey: globalOpts.apiKey,
314
+ baseUrl: globalOpts.baseUrl,
315
+ dryRun: globalOpts.dryRun,
316
+ verbose: globalOpts.verbose,
317
+ body
318
+ });
336
319
  printJson(data);
337
320
  } catch (error) {
338
321
  printError(error);
@@ -352,16 +335,12 @@ ${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
352
335
  return;
353
336
  }
354
337
  }
355
- await apiRequest(
356
- "DELETE",
357
- `policy-groups/${opts.id}`,
358
- {
359
- apiKey: globalOpts.apiKey,
360
- baseUrl: globalOpts.baseUrl,
361
- dryRun: globalOpts.dryRun,
362
- verbose: globalOpts.verbose
363
- }
364
- );
338
+ await apiRequest("DELETE", `policy-groups/${opts.id}`, {
339
+ apiKey: globalOpts.apiKey,
340
+ baseUrl: globalOpts.baseUrl,
341
+ dryRun: globalOpts.dryRun,
342
+ verbose: globalOpts.verbose
343
+ });
365
344
  console.log(`\u2713 Group ${opts.id} deleted.`);
366
345
  } catch (error) {
367
346
  printError(error);
@@ -406,16 +385,12 @@ ${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
406
385
  return;
407
386
  }
408
387
  }
409
- const data = await apiRequest(
410
- "DELETE",
411
- `policy-groups/${opts.groupId}/ab-test`,
412
- {
413
- apiKey: globalOpts.apiKey,
414
- baseUrl: globalOpts.baseUrl,
415
- dryRun: globalOpts.dryRun,
416
- verbose: globalOpts.verbose
417
- }
418
- );
388
+ const data = await apiRequest("DELETE", `policy-groups/${opts.groupId}/ab-test`, {
389
+ apiKey: globalOpts.apiKey,
390
+ baseUrl: globalOpts.baseUrl,
391
+ dryRun: globalOpts.dryRun,
392
+ verbose: globalOpts.verbose
393
+ });
419
394
  printJson(data);
420
395
  } catch (error) {
421
396
  printError(error);
@@ -563,16 +538,12 @@ ${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
563
538
  return;
564
539
  }
565
540
  }
566
- await apiRequest(
567
- "DELETE",
568
- `policy-groups/${opts.groupId}/versions/${opts.id}`,
569
- {
570
- apiKey: globalOpts.apiKey,
571
- baseUrl: globalOpts.baseUrl,
572
- dryRun: globalOpts.dryRun,
573
- verbose: globalOpts.verbose
574
- }
575
- );
541
+ await apiRequest("DELETE", `policy-groups/${opts.groupId}/versions/${opts.id}`, {
542
+ apiKey: globalOpts.apiKey,
543
+ baseUrl: globalOpts.baseUrl,
544
+ dryRun: globalOpts.dryRun,
545
+ verbose: globalOpts.verbose
546
+ });
576
547
  console.log(`\u2713 Version ${opts.id} deleted.`);
577
548
  } catch (error) {
578
549
  printError(error);
@@ -809,17 +780,13 @@ function registerFactCommands(program) {
809
780
  size: opts.size
810
781
  };
811
782
  if (opts.keyword) params.keyword = opts.keyword;
812
- const data = await apiRequest(
813
- "GET",
814
- "schema/facts",
815
- {
816
- apiKey: globalOpts.apiKey,
817
- baseUrl: globalOpts.baseUrl,
818
- dryRun: globalOpts.dryRun,
819
- verbose: globalOpts.verbose,
820
- params
821
- }
822
- );
783
+ const data = await apiRequest("GET", "schema/facts", {
784
+ apiKey: globalOpts.apiKey,
785
+ baseUrl: globalOpts.baseUrl,
786
+ dryRun: globalOpts.dryRun,
787
+ verbose: globalOpts.verbose,
788
+ params
789
+ });
823
790
  if (format === "table") {
824
791
  printTable(
825
792
  ["ID", "Key", "Name", "Type", "System", "Required"],
@@ -847,17 +814,13 @@ ${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
847
814
  try {
848
815
  const globalOpts = program.opts();
849
816
  const body = opts.json ? JSON.parse(opts.json) : buildCreateBody2(opts);
850
- const data = await apiRequest(
851
- "POST",
852
- "schema/facts",
853
- {
854
- apiKey: globalOpts.apiKey,
855
- baseUrl: globalOpts.baseUrl,
856
- dryRun: globalOpts.dryRun,
857
- verbose: globalOpts.verbose,
858
- body
859
- }
860
- );
817
+ const data = await apiRequest("POST", "schema/facts", {
818
+ apiKey: globalOpts.apiKey,
819
+ baseUrl: globalOpts.baseUrl,
820
+ dryRun: globalOpts.dryRun,
821
+ verbose: globalOpts.verbose,
822
+ body
823
+ });
861
824
  printJson(data);
862
825
  } catch (error) {
863
826
  printError(error);
@@ -868,17 +831,13 @@ ${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
868
831
  try {
869
832
  const globalOpts = program.opts();
870
833
  const body = opts.json ? JSON.parse(opts.json) : buildUpdateBody2(opts);
871
- const data = await apiRequest(
872
- "PUT",
873
- `schema/facts/${opts.id}`,
874
- {
875
- apiKey: globalOpts.apiKey,
876
- baseUrl: globalOpts.baseUrl,
877
- dryRun: globalOpts.dryRun,
878
- verbose: globalOpts.verbose,
879
- body
880
- }
881
- );
834
+ const data = await apiRequest("PUT", `schema/facts/${opts.id}`, {
835
+ apiKey: globalOpts.apiKey,
836
+ baseUrl: globalOpts.baseUrl,
837
+ dryRun: globalOpts.dryRun,
838
+ verbose: globalOpts.verbose,
839
+ body
840
+ });
882
841
  printJson(data);
883
842
  } catch (error) {
884
843
  printError(error);
@@ -898,16 +857,12 @@ ${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
898
857
  return;
899
858
  }
900
859
  }
901
- await apiRequest(
902
- "DELETE",
903
- `schema/facts/${opts.id}`,
904
- {
905
- apiKey: globalOpts.apiKey,
906
- baseUrl: globalOpts.baseUrl,
907
- dryRun: globalOpts.dryRun,
908
- verbose: globalOpts.verbose
909
- }
910
- );
860
+ await apiRequest("DELETE", `schema/facts/${opts.id}`, {
861
+ apiKey: globalOpts.apiKey,
862
+ baseUrl: globalOpts.baseUrl,
863
+ dryRun: globalOpts.dryRun,
864
+ verbose: globalOpts.verbose
865
+ });
911
866
  console.log(`\u2713 Fact ${opts.id} deleted.`);
912
867
  } catch (error) {
913
868
  printError(error);
@@ -917,16 +872,12 @@ ${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
917
872
  facts.command("action-metadata").description("Get action runtime fact metadata").action(async () => {
918
873
  try {
919
874
  const globalOpts = program.opts();
920
- const data = await apiRequest(
921
- "GET",
922
- "schema/action-metadata",
923
- {
924
- apiKey: globalOpts.apiKey,
925
- baseUrl: globalOpts.baseUrl,
926
- dryRun: globalOpts.dryRun,
927
- verbose: globalOpts.verbose
928
- }
929
- );
875
+ const data = await apiRequest("GET", "schema/action-metadata", {
876
+ apiKey: globalOpts.apiKey,
877
+ baseUrl: globalOpts.baseUrl,
878
+ dryRun: globalOpts.dryRun,
879
+ verbose: globalOpts.verbose
880
+ });
930
881
  printJson(data);
931
882
  } catch (error) {
932
883
  printError(error);
@@ -982,17 +933,13 @@ function registerDeployCommands(program) {
982
933
  deploy.command("live").description("Deploy an ACTIVE version to live traffic").requiredOption("--group-id <groupId>", "Policy group ID").requiredOption("--version-id <versionId>", "Version ID to deploy").option("--memo <memo>", "Deployment memo").action(async (opts) => {
983
934
  try {
984
935
  const globalOpts = program.opts();
985
- await apiRequest(
986
- "POST",
987
- `policy-groups/${opts.groupId}/deploy`,
988
- {
989
- apiKey: globalOpts.apiKey,
990
- baseUrl: globalOpts.baseUrl,
991
- dryRun: globalOpts.dryRun,
992
- verbose: globalOpts.verbose,
993
- body: { versionId: opts.versionId, memo: opts.memo ?? "" }
994
- }
995
- );
936
+ await apiRequest("POST", `policy-groups/${opts.groupId}/deploy`, {
937
+ apiKey: globalOpts.apiKey,
938
+ baseUrl: globalOpts.baseUrl,
939
+ dryRun: globalOpts.dryRun,
940
+ verbose: globalOpts.verbose,
941
+ body: { versionId: opts.versionId, memo: opts.memo ?? "" }
942
+ });
996
943
  console.log(`\u2713 Version ${opts.versionId} deployed to live.`);
997
944
  } catch (error) {
998
945
  printError(error);
@@ -1012,17 +959,13 @@ function registerDeployCommands(program) {
1012
959
  return;
1013
960
  }
1014
961
  }
1015
- await apiRequest(
1016
- "POST",
1017
- `policy-groups/${opts.groupId}/rollback`,
1018
- {
1019
- apiKey: globalOpts.apiKey,
1020
- baseUrl: globalOpts.baseUrl,
1021
- dryRun: globalOpts.dryRun,
1022
- verbose: globalOpts.verbose,
1023
- body: { memo: opts.memo ?? "" }
1024
- }
1025
- );
962
+ await apiRequest("POST", `policy-groups/${opts.groupId}/rollback`, {
963
+ apiKey: globalOpts.apiKey,
964
+ baseUrl: globalOpts.baseUrl,
965
+ dryRun: globalOpts.dryRun,
966
+ verbose: globalOpts.verbose,
967
+ body: { memo: opts.memo ?? "" }
968
+ });
1026
969
  console.log(`\u2713 Group ${opts.groupId} rolled back.`);
1027
970
  } catch (error) {
1028
971
  printError(error);
@@ -1042,24 +985,23 @@ function registerDeployCommands(program) {
1042
985
  return;
1043
986
  }
1044
987
  }
1045
- await apiRequest(
1046
- "POST",
1047
- `policy-groups/${opts.groupId}/undeploy`,
1048
- {
1049
- apiKey: globalOpts.apiKey,
1050
- baseUrl: globalOpts.baseUrl,
1051
- dryRun: globalOpts.dryRun,
1052
- verbose: globalOpts.verbose,
1053
- body: { memo: opts.memo ?? "" }
1054
- }
1055
- );
988
+ await apiRequest("POST", `policy-groups/${opts.groupId}/undeploy`, {
989
+ apiKey: globalOpts.apiKey,
990
+ baseUrl: globalOpts.baseUrl,
991
+ dryRun: globalOpts.dryRun,
992
+ verbose: globalOpts.verbose,
993
+ body: { memo: opts.memo ?? "" }
994
+ });
1056
995
  console.log(`\u2713 Group ${opts.groupId} undeployed.`);
1057
996
  } catch (error) {
1058
997
  printError(error);
1059
998
  process.exit(1);
1060
999
  }
1061
1000
  });
1062
- deploy.command("history").description("List deployment history").option("--group-id <groupId>", "Filter by policy group").option("--types <types>", "Filter by types (comma-separated: PUBLISH,DEPLOY,ROLLBACK,UNDEPLOY)").option("--start-date <date>", "Start date (yyyy-MM-dd)").option("--end-date <date>", "End date (yyyy-MM-dd)").option("--page <number>", "Page number", "0").option("--size <number>", "Page size", "20").action(async (opts) => {
1001
+ deploy.command("history").description("List deployment history").option("--group-id <groupId>", "Filter by policy group").option(
1002
+ "--types <types>",
1003
+ "Filter by types (comma-separated: PUBLISH,DEPLOY,ROLLBACK,UNDEPLOY)"
1004
+ ).option("--start-date <date>", "Start date (yyyy-MM-dd)").option("--end-date <date>", "End date (yyyy-MM-dd)").option("--page <number>", "Page number", "0").option("--size <number>", "Page size", "20").action(async (opts) => {
1063
1005
  try {
1064
1006
  const globalOpts = program.opts();
1065
1007
  const format = globalOpts.format ?? "json";
@@ -1071,17 +1013,13 @@ function registerDeployCommands(program) {
1071
1013
  if (opts.types) params.types = opts.types;
1072
1014
  if (opts.startDate) params.startDate = opts.startDate;
1073
1015
  if (opts.endDate) params.endDate = opts.endDate;
1074
- const data = await apiRequest(
1075
- "GET",
1076
- "deployments",
1077
- {
1078
- apiKey: globalOpts.apiKey,
1079
- baseUrl: globalOpts.baseUrl,
1080
- dryRun: globalOpts.dryRun,
1081
- verbose: globalOpts.verbose,
1082
- params
1083
- }
1084
- );
1016
+ const data = await apiRequest("GET", "deployments", {
1017
+ apiKey: globalOpts.apiKey,
1018
+ baseUrl: globalOpts.baseUrl,
1019
+ dryRun: globalOpts.dryRun,
1020
+ verbose: globalOpts.verbose,
1021
+ params
1022
+ });
1085
1023
  if (format === "table") {
1086
1024
  printTable(
1087
1025
  ["ID", "Type", "Group", "Version", "By", "At"],
@@ -1108,16 +1046,12 @@ ${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
1108
1046
  deploy.command("detail").description("Get deployment detail").requiredOption("--id <deploymentId>", "Deployment ID").action(async (opts) => {
1109
1047
  try {
1110
1048
  const globalOpts = program.opts();
1111
- const data = await apiRequest(
1112
- "GET",
1113
- `deployments/${opts.id}`,
1114
- {
1115
- apiKey: globalOpts.apiKey,
1116
- baseUrl: globalOpts.baseUrl,
1117
- dryRun: globalOpts.dryRun,
1118
- verbose: globalOpts.verbose
1119
- }
1120
- );
1049
+ const data = await apiRequest("GET", `deployments/${opts.id}`, {
1050
+ apiKey: globalOpts.apiKey,
1051
+ baseUrl: globalOpts.baseUrl,
1052
+ dryRun: globalOpts.dryRun,
1053
+ verbose: globalOpts.verbose
1054
+ });
1121
1055
  printJson(data);
1122
1056
  } catch (error) {
1123
1057
  printError(error);
@@ -1128,16 +1062,12 @@ ${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
1128
1062
  try {
1129
1063
  const globalOpts = program.opts();
1130
1064
  const format = globalOpts.format ?? "json";
1131
- const data = await apiRequest(
1132
- "GET",
1133
- "deployments/overview",
1134
- {
1135
- apiKey: globalOpts.apiKey,
1136
- baseUrl: globalOpts.baseUrl,
1137
- dryRun: globalOpts.dryRun,
1138
- verbose: globalOpts.verbose
1139
- }
1140
- );
1065
+ const data = await apiRequest("GET", "deployments/overview", {
1066
+ apiKey: globalOpts.apiKey,
1067
+ baseUrl: globalOpts.baseUrl,
1068
+ dryRun: globalOpts.dryRun,
1069
+ verbose: globalOpts.verbose
1070
+ });
1141
1071
  if (format === "table") {
1142
1072
  printTable(
1143
1073
  ["Group", "Name", "Status", "Current Version", "Last Deploy"],
@@ -1179,20 +1109,16 @@ ${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
1179
1109
  deploy.command("diff").description("Compare snapshot diff between two versions").requiredOption("--base <versionId>", "Base version ID").requiredOption("--target <versionId>", "Target version ID").action(async (opts) => {
1180
1110
  try {
1181
1111
  const globalOpts = program.opts();
1182
- const data = await apiRequest(
1183
- "GET",
1184
- "deployments/diff",
1185
- {
1186
- apiKey: globalOpts.apiKey,
1187
- baseUrl: globalOpts.baseUrl,
1188
- dryRun: globalOpts.dryRun,
1189
- verbose: globalOpts.verbose,
1190
- params: {
1191
- baseVersionId: opts.base,
1192
- targetVersionId: opts.target
1193
- }
1112
+ const data = await apiRequest("GET", "deployments/diff", {
1113
+ apiKey: globalOpts.apiKey,
1114
+ baseUrl: globalOpts.baseUrl,
1115
+ dryRun: globalOpts.dryRun,
1116
+ verbose: globalOpts.verbose,
1117
+ params: {
1118
+ baseVersionId: opts.base,
1119
+ targetVersionId: opts.target
1194
1120
  }
1195
- );
1121
+ });
1196
1122
  printJson(data);
1197
1123
  } catch (error) {
1198
1124
  printError(error);
@@ -1237,19 +1163,17 @@ function registerAnalyticsCommands(program) {
1237
1163
  const globalOpts = program.opts();
1238
1164
  const body = resolveBody(opts);
1239
1165
  if (!body.facts || !body.versionIdA || !body.versionIdB) {
1240
- throw new Error('Request body must include "facts", "versionIdA", "versionIdB". Use --json or --file.');
1166
+ throw new Error(
1167
+ 'Request body must include "facts", "versionIdA", "versionIdB". Use --json or --file.'
1168
+ );
1241
1169
  }
1242
- const data = await apiRequest(
1243
- "POST",
1244
- "analytics/dry-run/compare",
1245
- {
1246
- apiKey: globalOpts.apiKey,
1247
- baseUrl: globalOpts.baseUrl,
1248
- dryRun: globalOpts.dryRun,
1249
- verbose: globalOpts.verbose,
1250
- body
1251
- }
1252
- );
1170
+ const data = await apiRequest("POST", "analytics/dry-run/compare", {
1171
+ apiKey: globalOpts.apiKey,
1172
+ baseUrl: globalOpts.baseUrl,
1173
+ dryRun: globalOpts.dryRun,
1174
+ verbose: globalOpts.verbose,
1175
+ body
1176
+ });
1253
1177
  printJson(data);
1254
1178
  } catch (error) {
1255
1179
  printError(error);
@@ -1296,17 +1220,13 @@ function registerAnalyticsCommands(program) {
1296
1220
  try {
1297
1221
  const globalOpts = program.opts();
1298
1222
  const body = resolveBody(opts);
1299
- const data = await apiRequest(
1300
- "POST",
1301
- "analytics/simulations",
1302
- {
1303
- apiKey: globalOpts.apiKey,
1304
- baseUrl: globalOpts.baseUrl,
1305
- dryRun: globalOpts.dryRun,
1306
- verbose: globalOpts.verbose,
1307
- body
1308
- }
1309
- );
1223
+ const data = await apiRequest("POST", "analytics/simulations", {
1224
+ apiKey: globalOpts.apiKey,
1225
+ baseUrl: globalOpts.baseUrl,
1226
+ dryRun: globalOpts.dryRun,
1227
+ verbose: globalOpts.verbose,
1228
+ body
1229
+ });
1310
1230
  console.log(`\u2713 Simulation started: ${data.simulationId} (${data.status})`);
1311
1231
  printJson(data);
1312
1232
  } catch (error) {
@@ -1340,20 +1260,32 @@ function registerAnalyticsCommands(program) {
1340
1260
  console.log(`Time: ${data.summary.executionTimeMs.toLocaleString()}ms`);
1341
1261
  }
1342
1262
  if (data.metricSummary) {
1343
- console.log(`
1344
- \u2500\u2500 Metric: ${data.metricSummary.targetVariable} (${data.metricSummary.aggregationType}) \u2500\u2500`);
1263
+ console.log(
1264
+ `
1265
+ \u2500\u2500 Metric: ${data.metricSummary.targetVariable} (${data.metricSummary.aggregationType}) \u2500\u2500`
1266
+ );
1345
1267
  console.log(`Baseline: ${data.metricSummary.baselineValue.toLocaleString()}`);
1346
1268
  console.log(`Simulated: ${data.metricSummary.simulatedValue.toLocaleString()}`);
1347
- console.log(`Delta: ${data.metricSummary.delta > 0 ? "+" : ""}${data.metricSummary.delta.toLocaleString()}`);
1348
- console.log(`Change: ${data.metricSummary.deltaPercentage > 0 ? "+" : ""}${data.metricSummary.deltaPercentage.toFixed(1)}%`);
1269
+ console.log(
1270
+ `Delta: ${data.metricSummary.delta > 0 ? "+" : ""}${data.metricSummary.delta.toLocaleString()}`
1271
+ );
1272
+ console.log(
1273
+ `Change: ${data.metricSummary.deltaPercentage > 0 ? "+" : ""}${data.metricSummary.deltaPercentage.toFixed(1)}%`
1274
+ );
1349
1275
  }
1350
1276
  if (data.policyImpact?.comparison) {
1351
1277
  const diff = data.policyImpact.comparison.difference;
1352
1278
  console.log(`
1353
1279
  \u2500\u2500 Impact \u2500\u2500`);
1354
- console.log(`Matched \u0394: ${diff.matchedCountDelta > 0 ? "+" : ""}${diff.matchedCountDelta}`);
1355
- console.log(`Rate \u0394: ${diff.matchedRateDelta > 0 ? "+" : ""}${diff.matchedRateDelta.toFixed(1)}%`);
1356
- console.log(`Metric \u0394: ${diff.metricValueDelta > 0 ? "+" : ""}${diff.metricValueDelta.toLocaleString()}`);
1280
+ console.log(
1281
+ `Matched \u0394: ${diff.matchedCountDelta > 0 ? "+" : ""}${diff.matchedCountDelta}`
1282
+ );
1283
+ console.log(
1284
+ `Rate \u0394: ${diff.matchedRateDelta > 0 ? "+" : ""}${diff.matchedRateDelta.toFixed(1)}%`
1285
+ );
1286
+ console.log(
1287
+ `Metric \u0394: ${diff.metricValueDelta > 0 ? "+" : ""}${diff.metricValueDelta.toLocaleString()}`
1288
+ );
1357
1289
  }
1358
1290
  if (data.ruleStats?.length) {
1359
1291
  console.log("");
@@ -1375,7 +1307,10 @@ function registerAnalyticsCommands(program) {
1375
1307
  process.exit(1);
1376
1308
  }
1377
1309
  });
1378
- sim.command("list").description("List simulation history").option("--status <status>", "Filter by status (PENDING, RUNNING, COMPLETED, FAILED, CANCELLED)").option("--from <date>", "Start date (yyyy-MM-dd)").option("--to <date>", "End date (yyyy-MM-dd)").option("--page <number>", "Page number", "0").option("--size <number>", "Page size", "20").action(async (opts) => {
1310
+ sim.command("list").description("List simulation history").option(
1311
+ "--status <status>",
1312
+ "Filter by status (PENDING, RUNNING, COMPLETED, FAILED, CANCELLED)"
1313
+ ).option("--from <date>", "Start date (yyyy-MM-dd)").option("--to <date>", "End date (yyyy-MM-dd)").option("--page <number>", "Page number", "0").option("--size <number>", "Page size", "20").action(async (opts) => {
1379
1314
  try {
1380
1315
  const globalOpts = program.opts();
1381
1316
  const format = globalOpts.format ?? "json";
@@ -1434,16 +1369,12 @@ ${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
1434
1369
  return;
1435
1370
  }
1436
1371
  }
1437
- await apiRequest(
1438
- "DELETE",
1439
- `analytics/simulations/${opts.id}`,
1440
- {
1441
- apiKey: globalOpts.apiKey,
1442
- baseUrl: globalOpts.baseUrl,
1443
- dryRun: globalOpts.dryRun,
1444
- verbose: globalOpts.verbose
1445
- }
1446
- );
1372
+ await apiRequest("DELETE", `analytics/simulations/${opts.id}`, {
1373
+ apiKey: globalOpts.apiKey,
1374
+ baseUrl: globalOpts.baseUrl,
1375
+ dryRun: globalOpts.dryRun,
1376
+ verbose: globalOpts.verbose
1377
+ });
1447
1378
  console.log(`\u2713 Simulation ${opts.id} cancelled.`);
1448
1379
  } catch (error) {
1449
1380
  printError(error);
@@ -1497,7 +1428,10 @@ ${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
1497
1428
  const blob = new Blob([fileBuffer], { type: contentType });
1498
1429
  const formData = new FormData();
1499
1430
  formData.append("file", blob, fileName);
1500
- const url = new URL("analytics/datasets/upload", baseUrl.endsWith("/") ? baseUrl : baseUrl + "/");
1431
+ const url = new URL(
1432
+ "analytics/datasets/upload",
1433
+ baseUrl.endsWith("/") ? baseUrl : baseUrl + "/"
1434
+ );
1501
1435
  if (globalOpts.verbose) {
1502
1436
  console.error(`\u2192 POST ${url.toString()}`);
1503
1437
  console.error(` File: ${filePath} (${fileBuffer.length} bytes)`);
@@ -1646,28 +1580,26 @@ ${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
1646
1580
  if (opts.groupId) params.policyGroupId = opts.groupId;
1647
1581
  if (opts.startDate) params.startDate = opts.startDate;
1648
1582
  if (opts.endDate) params.endDate = opts.endDate;
1649
- const data = await apiRequest(
1650
- "GET",
1651
- "execution/history/stats",
1652
- {
1653
- apiKey: globalOpts.apiKey,
1654
- baseUrl: globalOpts.baseUrl,
1655
- dryRun: globalOpts.dryRun,
1656
- verbose: globalOpts.verbose,
1657
- params
1658
- }
1659
- );
1583
+ const data = await apiRequest("GET", "execution/history/stats", {
1584
+ apiKey: globalOpts.apiKey,
1585
+ baseUrl: globalOpts.baseUrl,
1586
+ dryRun: globalOpts.dryRun,
1587
+ verbose: globalOpts.verbose,
1588
+ params
1589
+ });
1660
1590
  if (format === "table") {
1661
1591
  printTable(
1662
1592
  ["Total", "Success", "No Match", "Failures", "Success Rate", "Avg Latency"],
1663
- [[
1664
- String(data.totalExecutions),
1665
- String(data.successCount),
1666
- String(data.noMatchCount),
1667
- String(data.failureCount),
1668
- `${data.successRate}%`,
1669
- `${data.avgLatencyMs}ms`
1670
- ]]
1593
+ [
1594
+ [
1595
+ String(data.totalExecutions),
1596
+ String(data.successCount),
1597
+ String(data.noMatchCount),
1598
+ String(data.failureCount),
1599
+ `${data.successRate}%`,
1600
+ `${data.avgLatencyMs}ms`
1601
+ ]
1602
+ ]
1671
1603
  );
1672
1604
  } else {
1673
1605
  printJson(data);
@@ -1683,7 +1615,10 @@ ${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
1683
1615
  import "commander";
1684
1616
  function registerIntegrationCommands(program) {
1685
1617
  const integrations = program.command("integrations").description("Manage external integrations");
1686
- integrations.command("list").description("List integrations").option("--type <type>", "Filter by type (COUPON, POINT, NOTIFICATION, CRM, MESSENGER, WEBHOOK)").option("--page <number>", "Page number", "0").option("--size <number>", "Page size", "20").action(async (opts) => {
1618
+ integrations.command("list").description("List integrations").option(
1619
+ "--type <type>",
1620
+ "Filter by type (COUPON, POINT, NOTIFICATION, CRM, MESSENGER, WEBHOOK)"
1621
+ ).option("--page <number>", "Page number", "0").option("--size <number>", "Page size", "20").action(async (opts) => {
1687
1622
  try {
1688
1623
  const globalOpts = program.opts();
1689
1624
  const format = globalOpts.format ?? "json";
@@ -1692,17 +1627,13 @@ function registerIntegrationCommands(program) {
1692
1627
  size: opts.size
1693
1628
  };
1694
1629
  if (opts.type) params.type = opts.type;
1695
- const data = await apiRequest(
1696
- "GET",
1697
- "integrations",
1698
- {
1699
- apiKey: globalOpts.apiKey,
1700
- baseUrl: globalOpts.baseUrl,
1701
- dryRun: globalOpts.dryRun,
1702
- verbose: globalOpts.verbose,
1703
- params
1704
- }
1705
- );
1630
+ const data = await apiRequest("GET", "integrations", {
1631
+ apiKey: globalOpts.apiKey,
1632
+ baseUrl: globalOpts.baseUrl,
1633
+ dryRun: globalOpts.dryRun,
1634
+ verbose: globalOpts.verbose,
1635
+ params
1636
+ });
1706
1637
  if (format === "table") {
1707
1638
  printTable(
1708
1639
  ["ID", "Name", "Type", "URL", "Active"],
@@ -1728,16 +1659,12 @@ ${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
1728
1659
  integrations.command("get").description("Get integration detail").requiredOption("--id <integrationId>", "Integration ID").action(async (opts) => {
1729
1660
  try {
1730
1661
  const globalOpts = program.opts();
1731
- const data = await apiRequest(
1732
- "GET",
1733
- `integrations/${opts.id}`,
1734
- {
1735
- apiKey: globalOpts.apiKey,
1736
- baseUrl: globalOpts.baseUrl,
1737
- dryRun: globalOpts.dryRun,
1738
- verbose: globalOpts.verbose
1739
- }
1740
- );
1662
+ const data = await apiRequest("GET", `integrations/${opts.id}`, {
1663
+ apiKey: globalOpts.apiKey,
1664
+ baseUrl: globalOpts.baseUrl,
1665
+ dryRun: globalOpts.dryRun,
1666
+ verbose: globalOpts.verbose
1667
+ });
1741
1668
  printJson(data);
1742
1669
  } catch (error) {
1743
1670
  printError(error);
@@ -1748,17 +1675,13 @@ ${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
1748
1675
  try {
1749
1676
  const globalOpts = program.opts();
1750
1677
  const body = JSON.parse(opts.json);
1751
- const data = await apiRequest(
1752
- "POST",
1753
- "integrations",
1754
- {
1755
- apiKey: globalOpts.apiKey,
1756
- baseUrl: globalOpts.baseUrl,
1757
- dryRun: globalOpts.dryRun,
1758
- verbose: globalOpts.verbose,
1759
- body
1760
- }
1761
- );
1678
+ const data = await apiRequest("POST", "integrations", {
1679
+ apiKey: globalOpts.apiKey,
1680
+ baseUrl: globalOpts.baseUrl,
1681
+ dryRun: globalOpts.dryRun,
1682
+ verbose: globalOpts.verbose,
1683
+ body
1684
+ });
1762
1685
  printJson(data);
1763
1686
  } catch (error) {
1764
1687
  printError(error);
@@ -1778,16 +1701,12 @@ ${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
1778
1701
  return;
1779
1702
  }
1780
1703
  }
1781
- await apiRequest(
1782
- "DELETE",
1783
- `integrations/${opts.id}`,
1784
- {
1785
- apiKey: globalOpts.apiKey,
1786
- baseUrl: globalOpts.baseUrl,
1787
- dryRun: globalOpts.dryRun,
1788
- verbose: globalOpts.verbose
1789
- }
1790
- );
1704
+ await apiRequest("DELETE", `integrations/${opts.id}`, {
1705
+ apiKey: globalOpts.apiKey,
1706
+ baseUrl: globalOpts.baseUrl,
1707
+ dryRun: globalOpts.dryRun,
1708
+ verbose: globalOpts.verbose
1709
+ });
1791
1710
  console.log(`\u2713 Integration ${opts.id} deleted.`);
1792
1711
  } catch (error) {
1793
1712
  printError(error);
@@ -1797,16 +1716,12 @@ ${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
1797
1716
  integrations.command("config-spec").description("Get integration configuration field specs").action(async () => {
1798
1717
  try {
1799
1718
  const globalOpts = program.opts();
1800
- const data = await apiRequest(
1801
- "GET",
1802
- "integrations/config-spec",
1803
- {
1804
- apiKey: globalOpts.apiKey,
1805
- baseUrl: globalOpts.baseUrl,
1806
- dryRun: globalOpts.dryRun,
1807
- verbose: globalOpts.verbose
1808
- }
1809
- );
1719
+ const data = await apiRequest("GET", "integrations/config-spec", {
1720
+ apiKey: globalOpts.apiKey,
1721
+ baseUrl: globalOpts.baseUrl,
1722
+ dryRun: globalOpts.dryRun,
1723
+ verbose: globalOpts.verbose
1724
+ });
1810
1725
  printJson(data);
1811
1726
  } catch (error) {
1812
1727
  printError(error);
@@ -1855,17 +1770,13 @@ function registerLogCommands(program) {
1855
1770
  if (opts.keyword) params.searchKeyword = opts.keyword;
1856
1771
  if (opts.startDate) params.startDate = opts.startDate;
1857
1772
  if (opts.endDate) params.endDate = opts.endDate;
1858
- const data = await apiRequest(
1859
- "GET",
1860
- "failure-logs",
1861
- {
1862
- apiKey: globalOpts.apiKey,
1863
- baseUrl: globalOpts.baseUrl,
1864
- dryRun: globalOpts.dryRun,
1865
- verbose: globalOpts.verbose,
1866
- params
1867
- }
1868
- );
1773
+ const data = await apiRequest("GET", "failure-logs", {
1774
+ apiKey: globalOpts.apiKey,
1775
+ baseUrl: globalOpts.baseUrl,
1776
+ dryRun: globalOpts.dryRun,
1777
+ verbose: globalOpts.verbose,
1778
+ params
1779
+ });
1869
1780
  if (format === "table") {
1870
1781
  printTable(
1871
1782
  ["ID", "Category", "Task", "Status", "Retries", "Error", "Created"],
@@ -1893,16 +1804,12 @@ ${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
1893
1804
  logs.command("get").description("Get failure log detail").requiredOption("--id <logId>", "Log ID").action(async (opts) => {
1894
1805
  try {
1895
1806
  const globalOpts = program.opts();
1896
- const data = await apiRequest(
1897
- "GET",
1898
- `failure-logs/${opts.id}`,
1899
- {
1900
- apiKey: globalOpts.apiKey,
1901
- baseUrl: globalOpts.baseUrl,
1902
- dryRun: globalOpts.dryRun,
1903
- verbose: globalOpts.verbose
1904
- }
1905
- );
1807
+ const data = await apiRequest("GET", `failure-logs/${opts.id}`, {
1808
+ apiKey: globalOpts.apiKey,
1809
+ baseUrl: globalOpts.baseUrl,
1810
+ dryRun: globalOpts.dryRun,
1811
+ verbose: globalOpts.verbose
1812
+ });
1906
1813
  printJson(data);
1907
1814
  } catch (error) {
1908
1815
  printError(error);
@@ -1933,17 +1840,13 @@ ${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
1933
1840
  try {
1934
1841
  const globalOpts = program.opts();
1935
1842
  const logIds = opts.ids.split(",").map((id) => id.trim());
1936
- const data = await apiRequest(
1937
- "POST",
1938
- "failure-logs/bulk-actions",
1939
- {
1940
- apiKey: globalOpts.apiKey,
1941
- baseUrl: globalOpts.baseUrl,
1942
- dryRun: globalOpts.dryRun,
1943
- verbose: globalOpts.verbose,
1944
- body: { logIds, action: opts.action }
1945
- }
1946
- );
1843
+ const data = await apiRequest("POST", "failure-logs/bulk-actions", {
1844
+ apiKey: globalOpts.apiKey,
1845
+ baseUrl: globalOpts.baseUrl,
1846
+ dryRun: globalOpts.dryRun,
1847
+ verbose: globalOpts.verbose,
1848
+ body: { logIds, action: opts.action }
1849
+ });
1947
1850
  printJson(data);
1948
1851
  } catch (error) {
1949
1852
  printError(error);
@@ -1968,7 +1871,10 @@ function createCallApiFromConfig() {
1968
1871
  try {
1969
1872
  const config = loadConfig();
1970
1873
  if (opts?.upload) {
1971
- const url = new URL(path, config.baseUrl.endsWith("/") ? config.baseUrl : config.baseUrl + "/");
1874
+ const url = new URL(
1875
+ path,
1876
+ config.baseUrl.endsWith("/") ? config.baseUrl : config.baseUrl + "/"
1877
+ );
1972
1878
  if (opts.params) {
1973
1879
  for (const [key, value] of Object.entries(opts.params)) {
1974
1880
  if (value !== void 0) url.searchParams.set(key, value);
@@ -2036,18 +1942,14 @@ function registerGroupTools(server, callApi) {
2036
1942
  "lexq_groups_list",
2037
1943
  {
2038
1944
  title: "List Policy Groups",
2039
- description: "List all policy groups. Supports pagination and optional status/keyword filters.",
1945
+ description: "List all policy groups with pagination.",
2040
1946
  inputSchema: {
2041
1947
  page: z.number().int().min(0).default(0).describe("Page number (0-indexed)"),
2042
- size: z.number().int().min(1).max(100).default(20).describe("Page size"),
2043
- status: z.enum(["ACTIVE", "DISABLED", "ARCHIVED"]).optional().describe("Filter by status"),
2044
- keyword: z.string().optional().describe("Search keyword")
1948
+ size: z.number().int().min(1).max(100).default(20).describe("Page size")
2045
1949
  }
2046
1950
  },
2047
- async ({ page, size, status, keyword }) => {
1951
+ async ({ page, size }) => {
2048
1952
  const params = paginationParams(page, size);
2049
- if (status) params.status = status;
2050
- if (keyword) params.keyword = keyword;
2051
1953
  return callApi("GET", "policy-groups", { params });
2052
1954
  }
2053
1955
  );
@@ -2088,8 +1990,7 @@ function registerGroupTools(server, callApi) {
2088
1990
  if (args.conflictResolutionStrategy !== void 0)
2089
1991
  body.conflictResolutionStrategy = args.conflictResolutionStrategy;
2090
1992
  if (args.maxSelections !== void 0) body.maxSelections = args.maxSelections;
2091
- if (args.activationGroupId !== void 0)
2092
- body.activationGroupId = args.activationGroupId;
1993
+ if (args.activationGroupId !== void 0) body.activationGroupId = args.activationGroupId;
2093
1994
  return callApi("POST", "policy-groups", { body });
2094
1995
  }
2095
1996
  );
@@ -2109,7 +2010,7 @@ function registerGroupTools(server, callApi) {
2109
2010
  maxSelections: z.number().int().min(1).optional().describe("Max selections")
2110
2011
  }
2111
2012
  },
2112
- async ({ groupId, ...body }) => callApi("PATCH", `policy-groups/${groupId}`, { body })
2013
+ async ({ groupId, ...body }) => callApi("PUT", `policy-groups/${groupId}`, { body })
2113
2014
  );
2114
2015
  server.registerTool(
2115
2016
  "lexq_groups_delete",
@@ -2126,41 +2027,37 @@ function registerGroupTools(server, callApi) {
2126
2027
  "lexq_ab_test_start",
2127
2028
  {
2128
2029
  title: "Start A/B Test",
2129
- description: "Start an A/B test on a policy group. Requires a challenger version ID and traffic split percentages.",
2030
+ description: "Start an A/B test on a policy group. Requires a challenger version ID and traffic rate.",
2130
2031
  inputSchema: {
2131
2032
  groupId: z.string().uuid().describe("Policy group ID"),
2132
- challengerVersionId: z.string().uuid().describe("Challenger version ID"),
2133
- controlWeight: z.number().int().min(1).max(99).describe("Control traffic weight (%)"),
2134
- challengerWeight: z.number().int().min(1).max(99).describe("Challenger traffic weight (%)"),
2135
- identityKey: z.string().optional().describe("Fact key for sticky assignment (e.g. customer_id)")
2033
+ testVersionId: z.string().uuid().describe("Challenger version ID to test"),
2034
+ trafficRate: z.number().int().min(1).max(99).describe("Traffic percentage routed to challenger (1-99)")
2136
2035
  }
2137
2036
  },
2138
- async ({ groupId, ...body }) => callApi("POST", `policy-groups/${groupId}/ab-test/start`, { body })
2037
+ async ({ groupId, ...body }) => callApi("POST", `policy-groups/${groupId}/ab-test`, { body })
2139
2038
  );
2140
2039
  server.registerTool(
2141
2040
  "lexq_ab_test_stop",
2142
2041
  {
2143
2042
  title: "Stop A/B Test",
2144
- description: "Stop a running A/B test. Specify which version to keep.",
2043
+ description: "Stop a running A/B test. All traffic is restored to the control (current) version.",
2145
2044
  inputSchema: {
2146
- groupId: z.string().uuid().describe("Policy group ID"),
2147
- winnerVersionId: z.string().uuid().describe("Version ID to keep as live")
2045
+ groupId: z.string().uuid().describe("Policy group ID")
2148
2046
  }
2149
2047
  },
2150
- async ({ groupId, ...body }) => callApi("POST", `policy-groups/${groupId}/ab-test/stop`, { body })
2048
+ async ({ groupId }) => callApi("DELETE", `policy-groups/${groupId}/ab-test`)
2151
2049
  );
2152
2050
  server.registerTool(
2153
2051
  "lexq_ab_test_adjust",
2154
2052
  {
2155
2053
  title: "Adjust A/B Test",
2156
- description: "Adjust traffic weights of a running A/B test.",
2054
+ description: "Adjust traffic rate of a running A/B test.",
2157
2055
  inputSchema: {
2158
2056
  groupId: z.string().uuid().describe("Policy group ID"),
2159
- controlWeight: z.number().int().min(1).max(99).describe("New control weight (%)"),
2160
- challengerWeight: z.number().int().min(1).max(99).describe("New challenger weight (%)")
2057
+ trafficRate: z.number().int().min(1).max(99).describe("New traffic percentage for challenger (1-99)")
2161
2058
  }
2162
2059
  },
2163
- async ({ groupId, ...body }) => callApi("POST", `policy-groups/${groupId}/ab-test/adjust`, { body })
2060
+ async ({ groupId, ...body }) => callApi("PATCH", `policy-groups/${groupId}/ab-test/traffic-rate`, { body })
2164
2061
  );
2165
2062
  }
2166
2063
 
@@ -2221,7 +2118,7 @@ function registerVersionTools(server, callApi) {
2221
2118
  effectiveTo: z2.string().optional().describe("New effective end date")
2222
2119
  }
2223
2120
  },
2224
- async ({ groupId, versionId, ...body }) => callApi("PATCH", `policy-groups/${groupId}/versions/${versionId}`, { body })
2121
+ async ({ groupId, versionId, ...body }) => callApi("PUT", `policy-groups/${groupId}/versions/${versionId}`, { body })
2225
2122
  );
2226
2123
  server.registerTool(
2227
2124
  "lexq_versions_delete",
@@ -2242,15 +2139,12 @@ function registerVersionTools(server, callApi) {
2242
2139
  description: "Clone an existing version to create a new DRAFT. Useful when the source version is already published.",
2243
2140
  inputSchema: {
2244
2141
  groupId: z2.string().uuid().describe("Policy group ID"),
2245
- versionId: z2.string().uuid().describe("Source version ID to clone"),
2246
- commitMessage: z2.string().optional().describe("Commit message for the cloned version")
2142
+ versionId: z2.string().uuid().describe("Source version ID to clone")
2247
2143
  }
2248
2144
  },
2249
- async ({ groupId, versionId, commitMessage }) => {
2250
- const body = {};
2251
- if (commitMessage !== void 0) body.commitMessage = commitMessage;
2145
+ async ({ groupId, versionId }) => {
2252
2146
  return callApi("POST", `policy-groups/${groupId}/versions/${versionId}/clone`, {
2253
- body
2147
+ body: {}
2254
2148
  });
2255
2149
  }
2256
2150
  );
@@ -2286,23 +2180,27 @@ function registerRuleTools(server, callApi) {
2286
2180
  ruleId: z3.string().uuid().describe("Rule ID")
2287
2181
  }
2288
2182
  },
2289
- async ({ groupId, versionId, ruleId }) => callApi(
2290
- "GET",
2291
- `policy-groups/${groupId}/versions/${versionId}/rules/${ruleId}`
2292
- )
2183
+ async ({ groupId, versionId, ruleId }) => callApi("GET", `policy-groups/${groupId}/versions/${versionId}/rules/${ruleId}`)
2293
2184
  );
2294
2185
  server.registerTool(
2295
2186
  "lexq_rules_create",
2296
2187
  {
2297
2188
  title: "Create Rule",
2298
- description: `Create a rule in a DRAFT version. Requires name, priority, condition tree, and actions array.
2299
-
2300
- Condition: { type: "SINGLE", field, operator, value, valueType } or { type: "GROUP", operator: "AND"|"OR", children: [...] }
2301
- Operators: EQUALS, NOT_EQUALS, GREATER_THAN, GREATER_THAN_OR_EQUAL, LESS_THAN, LESS_THAN_OR_EQUAL, CONTAINS, IN, NOT_IN
2302
- Value types: STRING, NUMBER, BOOLEAN, LIST_STRING, LIST_NUMBER
2303
-
2304
- Actions: [{ type, parameters }]
2305
- Types: DISCOUNT, POINT, COUPON_ISSUE, BLOCK, NOTIFICATION, WEBHOOK, SET_FACT, ADD_TAG`,
2189
+ description: `Create a rule in a DRAFT version. Requires name, priority, condition tree, and actions array.
2190
+ Condition: { type: "SINGLE", field, operator, value, valueType } or { type: "GROUP", operator: "AND"|"OR", children: [...] }
2191
+ Operators: EQUALS, NOT_EQUALS, GREATER_THAN, GREATER_THAN_OR_EQUAL, LESS_THAN, LESS_THAN_OR_EQUAL, CONTAINS, IN, NOT_IN
2192
+ Value types: STRING, NUMBER, BOOLEAN, LIST_STRING, LIST_NUMBER
2193
+
2194
+ Actions: [{ type, parameters }]
2195
+
2196
+ Action parameter schemas:
2197
+ - DISCOUNT: { refVar: string, method: "PERCENTAGE"|"AMOUNT", rate?: number (when PERCENTAGE), value?: number (when AMOUNT) }
2198
+ - POINT: { refVar: string, targetVar: string, method: "PERCENTAGE"|"AMOUNT", rate?: number (when PERCENTAGE), value?: number (when AMOUNT), integrationId: uuid }
2199
+ - COUPON_ISSUE: { couponId: string, integrationId: uuid }- BLOCK: { reason: string }
2200
+ - NOTIFICATION: { channel: "SMS"|"EMAIL"|"PUSH"|"KAKAO", targetVar: string, templateId: string, integrationId: uuid }
2201
+ - WEBHOOK: { url: string, method: "POST" }
2202
+ - SET_FACT: { key: string, value: string|number|boolean }
2203
+ - ADD_TAG: { tag: string, targetVar: string }`,
2306
2204
  inputSchema: {
2307
2205
  groupId: z3.string().uuid().describe("Policy group ID"),
2308
2206
  versionId: z3.string().uuid().describe("Version ID"),
@@ -2313,11 +2211,7 @@ Types: DISCOUNT, POINT, COUPON_ISSUE, BLOCK, NOTIFICATION, WEBHOOK, SET_FACT, AD
2313
2211
  },
2314
2212
  async ({ groupId, versionId, rule }) => {
2315
2213
  const body = JSON.parse(rule);
2316
- return callApi(
2317
- "POST",
2318
- `policy-groups/${groupId}/versions/${versionId}/rules`,
2319
- { body }
2320
- );
2214
+ return callApi("POST", `policy-groups/${groupId}/versions/${versionId}/rules`, { body });
2321
2215
  }
2322
2216
  );
2323
2217
  server.registerTool(
@@ -2336,11 +2230,9 @@ Types: DISCOUNT, POINT, COUPON_ISSUE, BLOCK, NOTIFICATION, WEBHOOK, SET_FACT, AD
2336
2230
  },
2337
2231
  async ({ groupId, versionId, ruleId, rule }) => {
2338
2232
  const body = JSON.parse(rule);
2339
- return callApi(
2340
- "PATCH",
2341
- `policy-groups/${groupId}/versions/${versionId}/rules/${ruleId}`,
2342
- { body }
2343
- );
2233
+ return callApi("PUT", `policy-groups/${groupId}/versions/${versionId}/rules/${ruleId}`, {
2234
+ body
2235
+ });
2344
2236
  }
2345
2237
  );
2346
2238
  server.registerTool(
@@ -2358,11 +2250,9 @@ Types: DISCOUNT, POINT, COUPON_ISSUE, BLOCK, NOTIFICATION, WEBHOOK, SET_FACT, AD
2358
2250
  async ({ groupId, versionId, ruleId, force }) => {
2359
2251
  const params = {};
2360
2252
  if (force) params.force = "true";
2361
- return callApi(
2362
- "DELETE",
2363
- `policy-groups/${groupId}/versions/${versionId}/rules/${ruleId}`,
2364
- { params }
2365
- );
2253
+ return callApi("DELETE", `policy-groups/${groupId}/versions/${versionId}/rules/${ruleId}`, {
2254
+ params
2255
+ });
2366
2256
  }
2367
2257
  );
2368
2258
  server.registerTool(
@@ -2381,11 +2271,9 @@ Types: DISCOUNT, POINT, COUPON_ISSUE, BLOCK, NOTIFICATION, WEBHOOK, SET_FACT, AD
2381
2271
  ruleId,
2382
2272
  priority: index
2383
2273
  }));
2384
- return callApi(
2385
- "PUT",
2386
- `policy-groups/${groupId}/versions/${versionId}/rules/reorder`,
2387
- { body: { rules } }
2388
- );
2274
+ return callApi("PATCH", `policy-groups/${groupId}/versions/${versionId}/rules/reorder`, {
2275
+ body: { rules }
2276
+ });
2389
2277
  }
2390
2278
  );
2391
2279
  server.registerTool(
@@ -2400,11 +2288,9 @@ Types: DISCOUNT, POINT, COUPON_ISSUE, BLOCK, NOTIFICATION, WEBHOOK, SET_FACT, AD
2400
2288
  isEnabled: z3.boolean().describe("true to enable, false to disable")
2401
2289
  }
2402
2290
  },
2403
- async ({ groupId, versionId, ruleId, isEnabled }) => callApi(
2404
- "PATCH",
2405
- `policy-groups/${groupId}/versions/${versionId}/rules/${ruleId}/toggle`,
2406
- { body: { isEnabled } }
2407
- )
2291
+ async ({ groupId, versionId, ruleId, isEnabled }) => callApi("PATCH", `policy-groups/${groupId}/versions/${versionId}/rules/${ruleId}/enabled`, {
2292
+ body: { isEnabled }
2293
+ })
2408
2294
  );
2409
2295
  }
2410
2296
 
@@ -2455,7 +2341,7 @@ function registerFactTools(server, callApi) {
2455
2341
  isRequired: z4.boolean().describe("Required flag")
2456
2342
  }
2457
2343
  },
2458
- async ({ factId, ...body }) => callApi("PATCH", `schema/facts/${factId}`, { body })
2344
+ async ({ factId, ...body }) => callApi("PUT", `schema/facts/${factId}`, { body })
2459
2345
  );
2460
2346
  server.registerTool(
2461
2347
  "lexq_facts_delete",
@@ -2484,11 +2370,7 @@ function registerDeployTools(server, callApi) {
2484
2370
  memo: z5.string().default("").describe("Deployment memo")
2485
2371
  }
2486
2372
  },
2487
- async ({ groupId, versionId, memo }) => callApi(
2488
- "POST",
2489
- `policy-groups/${groupId}/versions/${versionId}/publish`,
2490
- { body: { memo } }
2491
- )
2373
+ async ({ groupId, versionId, memo }) => callApi("POST", `policy-groups/${groupId}/versions/${versionId}/publish`, { body: { memo } })
2492
2374
  );
2493
2375
  server.registerTool(
2494
2376
  "lexq_deploy_live",
@@ -2628,10 +2510,7 @@ Always dry-run before publishing to validate rule behavior.`,
2628
2510
  versionId: z6.string().uuid().describe("Version ID")
2629
2511
  }
2630
2512
  },
2631
- async ({ groupId, versionId }) => callApi(
2632
- "GET",
2633
- `analytics/groups/${groupId}/versions/${versionId}/requirements`
2634
- )
2513
+ async ({ groupId, versionId }) => callApi("GET", `analytics/groups/${groupId}/versions/${versionId}/requirements`)
2635
2514
  );
2636
2515
  server.registerTool(
2637
2516
  "lexq_simulation_start",
@@ -2746,11 +2625,9 @@ JSON example:
2746
2625
  format: z6.enum(["csv", "json"]).default("csv").describe("Template format")
2747
2626
  }
2748
2627
  },
2749
- async ({ groupId, versionId, format }) => callApi(
2750
- "GET",
2751
- `analytics/groups/${groupId}/versions/${versionId}/dataset-template`,
2752
- { params: { format } }
2753
- )
2628
+ async ({ groupId, versionId, format }) => callApi("GET", `analytics/groups/${groupId}/versions/${versionId}/dataset-template`, {
2629
+ params: { format }
2630
+ })
2754
2631
  );
2755
2632
  }
2756
2633
 
@@ -2978,9 +2855,7 @@ function registerAllTools(server, callApi) {
2978
2855
  var __dirname = dirname(fileURLToPath(import.meta.url));
2979
2856
  function getVersion() {
2980
2857
  try {
2981
- const pkg = JSON.parse(
2982
- readFileSync3(join2(__dirname, "..", "package.json"), "utf-8")
2983
- );
2858
+ const pkg = JSON.parse(readFileSync3(join2(__dirname, "..", "package.json"), "utf-8"));
2984
2859
  return pkg.version;
2985
2860
  } catch {
2986
2861
  return "0.1.0";