@lexq/cli 0.1.12 → 0.1.13

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);
@@ -2088,8 +1994,7 @@ function registerGroupTools(server, callApi) {
2088
1994
  if (args.conflictResolutionStrategy !== void 0)
2089
1995
  body.conflictResolutionStrategy = args.conflictResolutionStrategy;
2090
1996
  if (args.maxSelections !== void 0) body.maxSelections = args.maxSelections;
2091
- if (args.activationGroupId !== void 0)
2092
- body.activationGroupId = args.activationGroupId;
1997
+ if (args.activationGroupId !== void 0) body.activationGroupId = args.activationGroupId;
2093
1998
  return callApi("POST", "policy-groups", { body });
2094
1999
  }
2095
2000
  );
@@ -2286,23 +2191,27 @@ function registerRuleTools(server, callApi) {
2286
2191
  ruleId: z3.string().uuid().describe("Rule ID")
2287
2192
  }
2288
2193
  },
2289
- async ({ groupId, versionId, ruleId }) => callApi(
2290
- "GET",
2291
- `policy-groups/${groupId}/versions/${versionId}/rules/${ruleId}`
2292
- )
2194
+ async ({ groupId, versionId, ruleId }) => callApi("GET", `policy-groups/${groupId}/versions/${versionId}/rules/${ruleId}`)
2293
2195
  );
2294
2196
  server.registerTool(
2295
2197
  "lexq_rules_create",
2296
2198
  {
2297
2199
  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`,
2200
+ description: `Create a rule in a DRAFT version. Requires name, priority, condition tree, and actions array.
2201
+ Condition: { type: "SINGLE", field, operator, value, valueType } or { type: "GROUP", operator: "AND"|"OR", children: [...] }
2202
+ Operators: EQUALS, NOT_EQUALS, GREATER_THAN, GREATER_THAN_OR_EQUAL, LESS_THAN, LESS_THAN_OR_EQUAL, CONTAINS, IN, NOT_IN
2203
+ Value types: STRING, NUMBER, BOOLEAN, LIST_STRING, LIST_NUMBER
2204
+
2205
+ Actions: [{ type, parameters }]
2206
+
2207
+ Action parameter schemas:
2208
+ - DISCOUNT: { refVar: string, method: "PERCENTAGE"|"AMOUNT", rate: number }
2209
+ - POINT: { refVar: string, targetVar: string, method: "PERCENTAGE"|"AMOUNT", rate?: number (when PERCENTAGE), value?: number (when AMOUNT), integrationId: uuid }
2210
+ - COUPON_ISSUE: { couponId: string, integrationId: uuid }- BLOCK: { reason: string }
2211
+ - NOTIFICATION: { channel: "SMS"|"EMAIL"|"PUSH"|"KAKAO", targetVar: string, templateId: string, integrationId: uuid }
2212
+ - WEBHOOK: { url: string, method: "POST" }
2213
+ - SET_FACT: { key: string, value: string|number|boolean }
2214
+ - ADD_TAG: { tag: string, targetVar: string }`,
2306
2215
  inputSchema: {
2307
2216
  groupId: z3.string().uuid().describe("Policy group ID"),
2308
2217
  versionId: z3.string().uuid().describe("Version ID"),
@@ -2313,11 +2222,7 @@ Types: DISCOUNT, POINT, COUPON_ISSUE, BLOCK, NOTIFICATION, WEBHOOK, SET_FACT, AD
2313
2222
  },
2314
2223
  async ({ groupId, versionId, rule }) => {
2315
2224
  const body = JSON.parse(rule);
2316
- return callApi(
2317
- "POST",
2318
- `policy-groups/${groupId}/versions/${versionId}/rules`,
2319
- { body }
2320
- );
2225
+ return callApi("POST", `policy-groups/${groupId}/versions/${versionId}/rules`, { body });
2321
2226
  }
2322
2227
  );
2323
2228
  server.registerTool(
@@ -2336,11 +2241,9 @@ Types: DISCOUNT, POINT, COUPON_ISSUE, BLOCK, NOTIFICATION, WEBHOOK, SET_FACT, AD
2336
2241
  },
2337
2242
  async ({ groupId, versionId, ruleId, rule }) => {
2338
2243
  const body = JSON.parse(rule);
2339
- return callApi(
2340
- "PATCH",
2341
- `policy-groups/${groupId}/versions/${versionId}/rules/${ruleId}`,
2342
- { body }
2343
- );
2244
+ return callApi("PATCH", `policy-groups/${groupId}/versions/${versionId}/rules/${ruleId}`, {
2245
+ body
2246
+ });
2344
2247
  }
2345
2248
  );
2346
2249
  server.registerTool(
@@ -2358,11 +2261,9 @@ Types: DISCOUNT, POINT, COUPON_ISSUE, BLOCK, NOTIFICATION, WEBHOOK, SET_FACT, AD
2358
2261
  async ({ groupId, versionId, ruleId, force }) => {
2359
2262
  const params = {};
2360
2263
  if (force) params.force = "true";
2361
- return callApi(
2362
- "DELETE",
2363
- `policy-groups/${groupId}/versions/${versionId}/rules/${ruleId}`,
2364
- { params }
2365
- );
2264
+ return callApi("DELETE", `policy-groups/${groupId}/versions/${versionId}/rules/${ruleId}`, {
2265
+ params
2266
+ });
2366
2267
  }
2367
2268
  );
2368
2269
  server.registerTool(
@@ -2381,11 +2282,9 @@ Types: DISCOUNT, POINT, COUPON_ISSUE, BLOCK, NOTIFICATION, WEBHOOK, SET_FACT, AD
2381
2282
  ruleId,
2382
2283
  priority: index
2383
2284
  }));
2384
- return callApi(
2385
- "PUT",
2386
- `policy-groups/${groupId}/versions/${versionId}/rules/reorder`,
2387
- { body: { rules } }
2388
- );
2285
+ return callApi("PUT", `policy-groups/${groupId}/versions/${versionId}/rules/reorder`, {
2286
+ body: { rules }
2287
+ });
2389
2288
  }
2390
2289
  );
2391
2290
  server.registerTool(
@@ -2400,11 +2299,9 @@ Types: DISCOUNT, POINT, COUPON_ISSUE, BLOCK, NOTIFICATION, WEBHOOK, SET_FACT, AD
2400
2299
  isEnabled: z3.boolean().describe("true to enable, false to disable")
2401
2300
  }
2402
2301
  },
2403
- async ({ groupId, versionId, ruleId, isEnabled }) => callApi(
2404
- "PATCH",
2405
- `policy-groups/${groupId}/versions/${versionId}/rules/${ruleId}/toggle`,
2406
- { body: { isEnabled } }
2407
- )
2302
+ async ({ groupId, versionId, ruleId, isEnabled }) => callApi("PATCH", `policy-groups/${groupId}/versions/${versionId}/rules/${ruleId}/toggle`, {
2303
+ body: { isEnabled }
2304
+ })
2408
2305
  );
2409
2306
  }
2410
2307
 
@@ -2484,11 +2381,7 @@ function registerDeployTools(server, callApi) {
2484
2381
  memo: z5.string().default("").describe("Deployment memo")
2485
2382
  }
2486
2383
  },
2487
- async ({ groupId, versionId, memo }) => callApi(
2488
- "POST",
2489
- `policy-groups/${groupId}/versions/${versionId}/publish`,
2490
- { body: { memo } }
2491
- )
2384
+ async ({ groupId, versionId, memo }) => callApi("POST", `policy-groups/${groupId}/versions/${versionId}/publish`, { body: { memo } })
2492
2385
  );
2493
2386
  server.registerTool(
2494
2387
  "lexq_deploy_live",
@@ -2628,10 +2521,7 @@ Always dry-run before publishing to validate rule behavior.`,
2628
2521
  versionId: z6.string().uuid().describe("Version ID")
2629
2522
  }
2630
2523
  },
2631
- async ({ groupId, versionId }) => callApi(
2632
- "GET",
2633
- `analytics/groups/${groupId}/versions/${versionId}/requirements`
2634
- )
2524
+ async ({ groupId, versionId }) => callApi("GET", `analytics/groups/${groupId}/versions/${versionId}/requirements`)
2635
2525
  );
2636
2526
  server.registerTool(
2637
2527
  "lexq_simulation_start",
@@ -2746,11 +2636,9 @@ JSON example:
2746
2636
  format: z6.enum(["csv", "json"]).default("csv").describe("Template format")
2747
2637
  }
2748
2638
  },
2749
- async ({ groupId, versionId, format }) => callApi(
2750
- "GET",
2751
- `analytics/groups/${groupId}/versions/${versionId}/dataset-template`,
2752
- { params: { format } }
2753
- )
2639
+ async ({ groupId, versionId, format }) => callApi("GET", `analytics/groups/${groupId}/versions/${versionId}/dataset-template`, {
2640
+ params: { format }
2641
+ })
2754
2642
  );
2755
2643
  }
2756
2644
 
@@ -2978,9 +2866,7 @@ function registerAllTools(server, callApi) {
2978
2866
  var __dirname = dirname(fileURLToPath(import.meta.url));
2979
2867
  function getVersion() {
2980
2868
  try {
2981
- const pkg = JSON.parse(
2982
- readFileSync3(join2(__dirname, "..", "package.json"), "utf-8")
2983
- );
2869
+ const pkg = JSON.parse(readFileSync3(join2(__dirname, "..", "package.json"), "utf-8"));
2984
2870
  return pkg.version;
2985
2871
  } catch {
2986
2872
  return "0.1.0";
@@ -87,8 +87,7 @@ function registerGroupTools(server, callApi) {
87
87
  if (args.conflictResolutionStrategy !== void 0)
88
88
  body.conflictResolutionStrategy = args.conflictResolutionStrategy;
89
89
  if (args.maxSelections !== void 0) body.maxSelections = args.maxSelections;
90
- if (args.activationGroupId !== void 0)
91
- body.activationGroupId = args.activationGroupId;
90
+ if (args.activationGroupId !== void 0) body.activationGroupId = args.activationGroupId;
92
91
  return callApi("POST", "policy-groups", { body });
93
92
  }
94
93
  );
@@ -285,23 +284,27 @@ function registerRuleTools(server, callApi) {
285
284
  ruleId: z3.string().uuid().describe("Rule ID")
286
285
  }
287
286
  },
288
- async ({ groupId, versionId, ruleId }) => callApi(
289
- "GET",
290
- `policy-groups/${groupId}/versions/${versionId}/rules/${ruleId}`
291
- )
287
+ async ({ groupId, versionId, ruleId }) => callApi("GET", `policy-groups/${groupId}/versions/${versionId}/rules/${ruleId}`)
292
288
  );
293
289
  server.registerTool(
294
290
  "lexq_rules_create",
295
291
  {
296
292
  title: "Create Rule",
297
- description: `Create a rule in a DRAFT version. Requires name, priority, condition tree, and actions array.
298
-
299
- Condition: { type: "SINGLE", field, operator, value, valueType } or { type: "GROUP", operator: "AND"|"OR", children: [...] }
300
- Operators: EQUALS, NOT_EQUALS, GREATER_THAN, GREATER_THAN_OR_EQUAL, LESS_THAN, LESS_THAN_OR_EQUAL, CONTAINS, IN, NOT_IN
301
- Value types: STRING, NUMBER, BOOLEAN, LIST_STRING, LIST_NUMBER
302
-
303
- Actions: [{ type, parameters }]
304
- Types: DISCOUNT, POINT, COUPON_ISSUE, BLOCK, NOTIFICATION, WEBHOOK, SET_FACT, ADD_TAG`,
293
+ description: `Create a rule in a DRAFT version. Requires name, priority, condition tree, and actions array.
294
+ Condition: { type: "SINGLE", field, operator, value, valueType } or { type: "GROUP", operator: "AND"|"OR", children: [...] }
295
+ Operators: EQUALS, NOT_EQUALS, GREATER_THAN, GREATER_THAN_OR_EQUAL, LESS_THAN, LESS_THAN_OR_EQUAL, CONTAINS, IN, NOT_IN
296
+ Value types: STRING, NUMBER, BOOLEAN, LIST_STRING, LIST_NUMBER
297
+
298
+ Actions: [{ type, parameters }]
299
+
300
+ Action parameter schemas:
301
+ - DISCOUNT: { refVar: string, method: "PERCENTAGE"|"AMOUNT", rate: number }
302
+ - POINT: { refVar: string, targetVar: string, method: "PERCENTAGE"|"AMOUNT", rate?: number (when PERCENTAGE), value?: number (when AMOUNT), integrationId: uuid }
303
+ - COUPON_ISSUE: { couponId: string, integrationId: uuid }- BLOCK: { reason: string }
304
+ - NOTIFICATION: { channel: "SMS"|"EMAIL"|"PUSH"|"KAKAO", targetVar: string, templateId: string, integrationId: uuid }
305
+ - WEBHOOK: { url: string, method: "POST" }
306
+ - SET_FACT: { key: string, value: string|number|boolean }
307
+ - ADD_TAG: { tag: string, targetVar: string }`,
305
308
  inputSchema: {
306
309
  groupId: z3.string().uuid().describe("Policy group ID"),
307
310
  versionId: z3.string().uuid().describe("Version ID"),
@@ -312,11 +315,7 @@ Types: DISCOUNT, POINT, COUPON_ISSUE, BLOCK, NOTIFICATION, WEBHOOK, SET_FACT, AD
312
315
  },
313
316
  async ({ groupId, versionId, rule }) => {
314
317
  const body = JSON.parse(rule);
315
- return callApi(
316
- "POST",
317
- `policy-groups/${groupId}/versions/${versionId}/rules`,
318
- { body }
319
- );
318
+ return callApi("POST", `policy-groups/${groupId}/versions/${versionId}/rules`, { body });
320
319
  }
321
320
  );
322
321
  server.registerTool(
@@ -335,11 +334,9 @@ Types: DISCOUNT, POINT, COUPON_ISSUE, BLOCK, NOTIFICATION, WEBHOOK, SET_FACT, AD
335
334
  },
336
335
  async ({ groupId, versionId, ruleId, rule }) => {
337
336
  const body = JSON.parse(rule);
338
- return callApi(
339
- "PATCH",
340
- `policy-groups/${groupId}/versions/${versionId}/rules/${ruleId}`,
341
- { body }
342
- );
337
+ return callApi("PATCH", `policy-groups/${groupId}/versions/${versionId}/rules/${ruleId}`, {
338
+ body
339
+ });
343
340
  }
344
341
  );
345
342
  server.registerTool(
@@ -357,11 +354,9 @@ Types: DISCOUNT, POINT, COUPON_ISSUE, BLOCK, NOTIFICATION, WEBHOOK, SET_FACT, AD
357
354
  async ({ groupId, versionId, ruleId, force }) => {
358
355
  const params = {};
359
356
  if (force) params.force = "true";
360
- return callApi(
361
- "DELETE",
362
- `policy-groups/${groupId}/versions/${versionId}/rules/${ruleId}`,
363
- { params }
364
- );
357
+ return callApi("DELETE", `policy-groups/${groupId}/versions/${versionId}/rules/${ruleId}`, {
358
+ params
359
+ });
365
360
  }
366
361
  );
367
362
  server.registerTool(
@@ -380,11 +375,9 @@ Types: DISCOUNT, POINT, COUPON_ISSUE, BLOCK, NOTIFICATION, WEBHOOK, SET_FACT, AD
380
375
  ruleId,
381
376
  priority: index
382
377
  }));
383
- return callApi(
384
- "PUT",
385
- `policy-groups/${groupId}/versions/${versionId}/rules/reorder`,
386
- { body: { rules } }
387
- );
378
+ return callApi("PUT", `policy-groups/${groupId}/versions/${versionId}/rules/reorder`, {
379
+ body: { rules }
380
+ });
388
381
  }
389
382
  );
390
383
  server.registerTool(
@@ -399,11 +392,9 @@ Types: DISCOUNT, POINT, COUPON_ISSUE, BLOCK, NOTIFICATION, WEBHOOK, SET_FACT, AD
399
392
  isEnabled: z3.boolean().describe("true to enable, false to disable")
400
393
  }
401
394
  },
402
- async ({ groupId, versionId, ruleId, isEnabled }) => callApi(
403
- "PATCH",
404
- `policy-groups/${groupId}/versions/${versionId}/rules/${ruleId}/toggle`,
405
- { body: { isEnabled } }
406
- )
395
+ async ({ groupId, versionId, ruleId, isEnabled }) => callApi("PATCH", `policy-groups/${groupId}/versions/${versionId}/rules/${ruleId}/toggle`, {
396
+ body: { isEnabled }
397
+ })
407
398
  );
408
399
  }
409
400
 
@@ -483,11 +474,7 @@ function registerDeployTools(server, callApi) {
483
474
  memo: z5.string().default("").describe("Deployment memo")
484
475
  }
485
476
  },
486
- async ({ groupId, versionId, memo }) => callApi(
487
- "POST",
488
- `policy-groups/${groupId}/versions/${versionId}/publish`,
489
- { body: { memo } }
490
- )
477
+ async ({ groupId, versionId, memo }) => callApi("POST", `policy-groups/${groupId}/versions/${versionId}/publish`, { body: { memo } })
491
478
  );
492
479
  server.registerTool(
493
480
  "lexq_deploy_live",
@@ -627,10 +614,7 @@ Always dry-run before publishing to validate rule behavior.`,
627
614
  versionId: z6.string().uuid().describe("Version ID")
628
615
  }
629
616
  },
630
- async ({ groupId, versionId }) => callApi(
631
- "GET",
632
- `analytics/groups/${groupId}/versions/${versionId}/requirements`
633
- )
617
+ async ({ groupId, versionId }) => callApi("GET", `analytics/groups/${groupId}/versions/${versionId}/requirements`)
634
618
  );
635
619
  server.registerTool(
636
620
  "lexq_simulation_start",
@@ -745,11 +729,9 @@ JSON example:
745
729
  format: z6.enum(["csv", "json"]).default("csv").describe("Template format")
746
730
  }
747
731
  },
748
- async ({ groupId, versionId, format }) => callApi(
749
- "GET",
750
- `analytics/groups/${groupId}/versions/${versionId}/dataset-template`,
751
- { params: { format } }
752
- )
732
+ async ({ groupId, versionId, format }) => callApi("GET", `analytics/groups/${groupId}/versions/${versionId}/dataset-template`, {
733
+ params: { format }
734
+ })
753
735
  );
754
736
  }
755
737
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lexq/cli",
3
- "version": "0.1.12",
3
+ "version": "0.1.13",
4
4
  "description": "LexQ CLI — manage policies, simulate rules, and deploy from the terminal. Built for humans and AI agents.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -48,6 +48,7 @@
48
48
  "cli-table3": "^0.6.5",
49
49
  "commander": "^13.1.0",
50
50
  "ora": "^8.2.0",
51
+ "prettier": "^3.8.1",
51
52
  "zod": "^3.25.76"
52
53
  },
53
54
  "devDependencies": {