@lexq/cli 0.1.13 → 0.1.15

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
@@ -910,7 +910,7 @@ function buildUpdateBody2(opts) {
910
910
  import "commander";
911
911
  function registerDeployCommands(program) {
912
912
  const deploy = program.command("deploy").description("Deployment lifecycle and history");
913
- deploy.command("publish").description("Publish a DRAFT version (DRAFT \u2192 ACTIVE)").requiredOption("--group-id <groupId>", "Policy group ID").requiredOption("--version-id <versionId>", "Version ID to publish").option("--memo <memo>", "Deployment memo").action(async (opts) => {
913
+ deploy.command("publish").description("Publish a DRAFT version (DRAFT \u2192 ACTIVE)").requiredOption("--group-id <groupId>", "Policy group ID").requiredOption("--version-id <versionId>", "Version ID to publish").requiredOption("--memo <memo>", "Publish Deployment memo").action(async (opts) => {
914
914
  try {
915
915
  const globalOpts = program.opts();
916
916
  await apiRequest(
@@ -921,7 +921,7 @@ function registerDeployCommands(program) {
921
921
  baseUrl: globalOpts.baseUrl,
922
922
  dryRun: globalOpts.dryRun,
923
923
  verbose: globalOpts.verbose,
924
- body: { memo: opts.memo ?? "" }
924
+ body: { memo: opts.memo }
925
925
  }
926
926
  );
927
927
  console.log(`\u2713 Version ${opts.versionId} published.`);
@@ -930,7 +930,7 @@ function registerDeployCommands(program) {
930
930
  process.exit(1);
931
931
  }
932
932
  });
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) => {
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").requiredOption("--memo <memo>", "Live Deployment memo").action(async (opts) => {
934
934
  try {
935
935
  const globalOpts = program.opts();
936
936
  await apiRequest("POST", `policy-groups/${opts.groupId}/deploy`, {
@@ -938,7 +938,7 @@ function registerDeployCommands(program) {
938
938
  baseUrl: globalOpts.baseUrl,
939
939
  dryRun: globalOpts.dryRun,
940
940
  verbose: globalOpts.verbose,
941
- body: { versionId: opts.versionId, memo: opts.memo ?? "" }
941
+ body: { versionId: opts.versionId, memo: opts.memo }
942
942
  });
943
943
  console.log(`\u2713 Version ${opts.versionId} deployed to live.`);
944
944
  } catch (error) {
@@ -946,7 +946,7 @@ function registerDeployCommands(program) {
946
946
  process.exit(1);
947
947
  }
948
948
  });
949
- deploy.command("rollback").description("Rollback to the previous deployed version").requiredOption("--group-id <groupId>", "Policy group ID").option("--memo <memo>", "Rollback reason").option("--force", "Skip confirmation prompt").action(async (opts) => {
949
+ deploy.command("rollback").description("Rollback to the previous deployed version").requiredOption("--group-id <groupId>", "Policy group ID").requiredOption("--memo <memo>", "Rollback reason").option("--force", "Skip confirmation prompt").action(async (opts) => {
950
950
  try {
951
951
  const globalOpts = program.opts();
952
952
  if (!opts.force) {
@@ -964,7 +964,7 @@ function registerDeployCommands(program) {
964
964
  baseUrl: globalOpts.baseUrl,
965
965
  dryRun: globalOpts.dryRun,
966
966
  verbose: globalOpts.verbose,
967
- body: { memo: opts.memo ?? "" }
967
+ body: { memo: opts.memo }
968
968
  });
969
969
  console.log(`\u2713 Group ${opts.groupId} rolled back.`);
970
970
  } catch (error) {
@@ -972,7 +972,7 @@ function registerDeployCommands(program) {
972
972
  process.exit(1);
973
973
  }
974
974
  });
975
- deploy.command("undeploy").description("Remove the live version from a group").requiredOption("--group-id <groupId>", "Policy group ID").option("--memo <memo>", "Undeploy reason").option("--force", "Skip confirmation prompt").action(async (opts) => {
975
+ deploy.command("undeploy").description("Remove the live version from a group").requiredOption("--group-id <groupId>", "Policy group ID").requiredOption("--memo <memo>", "Undeploy reason").option("--force", "Skip confirmation prompt").action(async (opts) => {
976
976
  try {
977
977
  const globalOpts = program.opts();
978
978
  if (!opts.force) {
@@ -990,7 +990,7 @@ function registerDeployCommands(program) {
990
990
  baseUrl: globalOpts.baseUrl,
991
991
  dryRun: globalOpts.dryRun,
992
992
  verbose: globalOpts.verbose,
993
- body: { memo: opts.memo ?? "" }
993
+ body: { memo: opts.memo }
994
994
  });
995
995
  console.log(`\u2713 Group ${opts.groupId} undeployed.`);
996
996
  } catch (error) {
@@ -1553,7 +1553,7 @@ ${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
1553
1553
  process.exit(1);
1554
1554
  }
1555
1555
  });
1556
- history.command("get").description("Get execution detail").requiredOption("--id <executionId>", "Execution history ID").action(async (opts) => {
1556
+ history.command("get").description("Get execution detail").requiredOption("--id <traceId>", "Trace ID").action(async (opts) => {
1557
1557
  try {
1558
1558
  const globalOpts = program.opts();
1559
1559
  const data = await apiRequest(
@@ -1942,18 +1942,14 @@ function registerGroupTools(server, callApi) {
1942
1942
  "lexq_groups_list",
1943
1943
  {
1944
1944
  title: "List Policy Groups",
1945
- description: "List all policy groups. Supports pagination and optional status/keyword filters.",
1945
+ description: "List all policy groups with pagination.",
1946
1946
  inputSchema: {
1947
1947
  page: z.number().int().min(0).default(0).describe("Page number (0-indexed)"),
1948
- size: z.number().int().min(1).max(100).default(20).describe("Page size"),
1949
- status: z.enum(["ACTIVE", "DISABLED", "ARCHIVED"]).optional().describe("Filter by status"),
1950
- keyword: z.string().optional().describe("Search keyword")
1948
+ size: z.number().int().min(1).max(100).default(20).describe("Page size")
1951
1949
  }
1952
1950
  },
1953
- async ({ page, size, status, keyword }) => {
1951
+ async ({ page, size }) => {
1954
1952
  const params = paginationParams(page, size);
1955
- if (status) params.status = status;
1956
- if (keyword) params.keyword = keyword;
1957
1953
  return callApi("GET", "policy-groups", { params });
1958
1954
  }
1959
1955
  );
@@ -1977,10 +1973,10 @@ function registerGroupTools(server, callApi) {
1977
1973
  name: z.string().describe("Group name (unique among non-ARCHIVED)"),
1978
1974
  priority: z.number().int().min(0).describe("Execution priority (lower = higher)"),
1979
1975
  description: z.string().optional().describe("Group description"),
1980
- conflictResolutionMode: z.enum(["NONE", "EXCLUSIVE", "MAX_N"]).optional().describe("Conflict resolution mode"),
1981
- conflictResolutionStrategy: z.enum(["FIRST_MATCH", "HIGHEST_PRIORITY", "MAX_BENEFIT"]).optional().describe("Strategy when mode is EXCLUSIVE or MAX_N"),
1982
- maxSelections: z.number().int().min(1).optional().describe("Max selections (required when mode is MAX_N)"),
1983
- activationGroupId: z.string().uuid().optional().describe("Activation group ID")
1976
+ activationMode: z.enum(["NONE", "EXCLUSIVE", "MAX_N"]).optional().describe("Conflict resolution mode"),
1977
+ activationStrategy: z.enum(["FIRST_MATCH", "HIGHEST_PRIORITY", "MAX_BENEFIT"]).optional().describe("Strategy when mode is EXCLUSIVE or MAX_N"),
1978
+ executionLimit: z.number().int().min(1).optional().describe("Max rule executions (required when mode is MAX_N)"),
1979
+ activationGroup: z.string().optional().describe("Activation group name")
1984
1980
  }
1985
1981
  },
1986
1982
  async (args) => {
@@ -1989,12 +1985,10 @@ function registerGroupTools(server, callApi) {
1989
1985
  priority: args.priority
1990
1986
  };
1991
1987
  if (args.description !== void 0) body.description = args.description;
1992
- if (args.conflictResolutionMode !== void 0)
1993
- body.conflictResolutionMode = args.conflictResolutionMode;
1994
- if (args.conflictResolutionStrategy !== void 0)
1995
- body.conflictResolutionStrategy = args.conflictResolutionStrategy;
1996
- if (args.maxSelections !== void 0) body.maxSelections = args.maxSelections;
1997
- if (args.activationGroupId !== void 0) body.activationGroupId = args.activationGroupId;
1988
+ if (args.activationMode !== void 0) body.activationMode = args.activationMode;
1989
+ if (args.activationStrategy !== void 0) body.activationStrategy = args.activationStrategy;
1990
+ if (args.executionLimit !== void 0) body.executionLimit = args.executionLimit;
1991
+ if (args.activationGroup !== void 0) body.activationGroup = args.activationGroup;
1998
1992
  return callApi("POST", "policy-groups", { body });
1999
1993
  }
2000
1994
  );
@@ -2002,19 +1996,19 @@ function registerGroupTools(server, callApi) {
2002
1996
  "lexq_groups_update",
2003
1997
  {
2004
1998
  title: "Update Policy Group",
2005
- description: "Update an existing policy group. Only provided fields are updated.",
1999
+ description: "Update a policy group. This is a full replacement \u2014 omitted optional fields will be set to null on the server.",
2006
2000
  inputSchema: {
2007
2001
  groupId: z.string().uuid().describe("Policy group ID"),
2008
2002
  name: z.string().optional().describe("New name"),
2009
2003
  priority: z.number().int().min(0).optional().describe("New priority"),
2010
2004
  description: z.string().optional().describe("New description"),
2011
2005
  status: z.enum(["ACTIVE", "DISABLED"]).optional().describe("Status (DISABLED = emergency stop)"),
2012
- conflictResolutionMode: z.enum(["NONE", "EXCLUSIVE", "MAX_N"]).optional().describe("Conflict resolution mode"),
2013
- conflictResolutionStrategy: z.enum(["FIRST_MATCH", "HIGHEST_PRIORITY", "MAX_BENEFIT"]).optional().describe("Strategy"),
2014
- maxSelections: z.number().int().min(1).optional().describe("Max selections")
2006
+ activationMode: z.enum(["NONE", "EXCLUSIVE", "MAX_N"]).optional().describe("Conflict resolution mode"),
2007
+ activationStrategy: z.enum(["FIRST_MATCH", "HIGHEST_PRIORITY", "MAX_BENEFIT"]).optional().describe("Strategy"),
2008
+ executionLimit: z.number().int().min(1).optional().describe("Max rule executions")
2015
2009
  }
2016
2010
  },
2017
- async ({ groupId, ...body }) => callApi("PATCH", `policy-groups/${groupId}`, { body })
2011
+ async ({ groupId, ...body }) => callApi("PUT", `policy-groups/${groupId}`, { body })
2018
2012
  );
2019
2013
  server.registerTool(
2020
2014
  "lexq_groups_delete",
@@ -2031,41 +2025,37 @@ function registerGroupTools(server, callApi) {
2031
2025
  "lexq_ab_test_start",
2032
2026
  {
2033
2027
  title: "Start A/B Test",
2034
- description: "Start an A/B test on a policy group. Requires a challenger version ID and traffic split percentages.",
2028
+ description: "Start an A/B test on a policy group. Requires a challenger version ID and traffic rate.",
2035
2029
  inputSchema: {
2036
2030
  groupId: z.string().uuid().describe("Policy group ID"),
2037
- challengerVersionId: z.string().uuid().describe("Challenger version ID"),
2038
- controlWeight: z.number().int().min(1).max(99).describe("Control traffic weight (%)"),
2039
- challengerWeight: z.number().int().min(1).max(99).describe("Challenger traffic weight (%)"),
2040
- identityKey: z.string().optional().describe("Fact key for sticky assignment (e.g. customer_id)")
2031
+ testVersionId: z.string().uuid().describe("Challenger version ID to test"),
2032
+ trafficRate: z.number().int().min(1).max(99).describe("Traffic percentage routed to challenger (1-99)")
2041
2033
  }
2042
2034
  },
2043
- async ({ groupId, ...body }) => callApi("POST", `policy-groups/${groupId}/ab-test/start`, { body })
2035
+ async ({ groupId, ...body }) => callApi("POST", `policy-groups/${groupId}/ab-test`, { body })
2044
2036
  );
2045
2037
  server.registerTool(
2046
2038
  "lexq_ab_test_stop",
2047
2039
  {
2048
2040
  title: "Stop A/B Test",
2049
- description: "Stop a running A/B test. Specify which version to keep.",
2041
+ description: "Stop a running A/B test. All traffic is restored to the control (current) version.",
2050
2042
  inputSchema: {
2051
- groupId: z.string().uuid().describe("Policy group ID"),
2052
- winnerVersionId: z.string().uuid().describe("Version ID to keep as live")
2043
+ groupId: z.string().uuid().describe("Policy group ID")
2053
2044
  }
2054
2045
  },
2055
- async ({ groupId, ...body }) => callApi("POST", `policy-groups/${groupId}/ab-test/stop`, { body })
2046
+ async ({ groupId }) => callApi("DELETE", `policy-groups/${groupId}/ab-test`)
2056
2047
  );
2057
2048
  server.registerTool(
2058
2049
  "lexq_ab_test_adjust",
2059
2050
  {
2060
2051
  title: "Adjust A/B Test",
2061
- description: "Adjust traffic weights of a running A/B test.",
2052
+ description: "Adjust traffic rate of a running A/B test.",
2062
2053
  inputSchema: {
2063
2054
  groupId: z.string().uuid().describe("Policy group ID"),
2064
- controlWeight: z.number().int().min(1).max(99).describe("New control weight (%)"),
2065
- challengerWeight: z.number().int().min(1).max(99).describe("New challenger weight (%)")
2055
+ trafficRate: z.number().int().min(1).max(99).describe("New traffic percentage for challenger (1-99)")
2066
2056
  }
2067
2057
  },
2068
- async ({ groupId, ...body }) => callApi("POST", `policy-groups/${groupId}/ab-test/adjust`, { body })
2058
+ async ({ groupId, ...body }) => callApi("PATCH", `policy-groups/${groupId}/ab-test/traffic-rate`, { body })
2069
2059
  );
2070
2060
  }
2071
2061
 
@@ -2126,7 +2116,7 @@ function registerVersionTools(server, callApi) {
2126
2116
  effectiveTo: z2.string().optional().describe("New effective end date")
2127
2117
  }
2128
2118
  },
2129
- async ({ groupId, versionId, ...body }) => callApi("PATCH", `policy-groups/${groupId}/versions/${versionId}`, { body })
2119
+ async ({ groupId, versionId, ...body }) => callApi("PUT", `policy-groups/${groupId}/versions/${versionId}`, { body })
2130
2120
  );
2131
2121
  server.registerTool(
2132
2122
  "lexq_versions_delete",
@@ -2147,15 +2137,12 @@ function registerVersionTools(server, callApi) {
2147
2137
  description: "Clone an existing version to create a new DRAFT. Useful when the source version is already published.",
2148
2138
  inputSchema: {
2149
2139
  groupId: z2.string().uuid().describe("Policy group ID"),
2150
- versionId: z2.string().uuid().describe("Source version ID to clone"),
2151
- commitMessage: z2.string().optional().describe("Commit message for the cloned version")
2140
+ versionId: z2.string().uuid().describe("Source version ID to clone")
2152
2141
  }
2153
2142
  },
2154
- async ({ groupId, versionId, commitMessage }) => {
2155
- const body = {};
2156
- if (commitMessage !== void 0) body.commitMessage = commitMessage;
2143
+ async ({ groupId, versionId }) => {
2157
2144
  return callApi("POST", `policy-groups/${groupId}/versions/${versionId}/clone`, {
2158
- body
2145
+ body: {}
2159
2146
  });
2160
2147
  }
2161
2148
  );
@@ -2197,17 +2184,21 @@ function registerRuleTools(server, callApi) {
2197
2184
  "lexq_rules_create",
2198
2185
  {
2199
2186
  title: "Create Rule",
2200
- description: `Create a rule in a DRAFT version. Requires name, priority, condition tree, and actions array.
2187
+ description: `Create a rule in a DRAFT version. Requires name, priority, condition tree, and actions array.
2188
+
2189
+ Note: Rules can reference fact keys that are not yet registered in Fact Definitions. The engine allows this for flexibility. However, registering facts via lexq_facts_create is recommended \u2014 it enables type validation, the Console UI autocomplete, and the dry-run requirements analyzer.
2190
+
2201
2191
  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
2192
+ Operators: EQUALS, NOT_EQUALS, GREATER_THAN, GREATER_THAN_OR_EQUAL, LESS_THAN, LESS_THAN_OR_EQUAL, CONTAINS, IN, NOT_IN
2203
2193
  Value types: STRING, NUMBER, BOOLEAN, LIST_STRING, LIST_NUMBER
2204
-
2194
+
2205
2195
  Actions: [{ type, parameters }]
2206
-
2196
+
2207
2197
  Action parameter schemas:
2208
- - DISCOUNT: { refVar: string, method: "PERCENTAGE"|"AMOUNT", rate: number }
2198
+ - DISCOUNT: { refVar: string, method: "PERCENTAGE"|"AMOUNT", rate?: number (when PERCENTAGE), value?: number (when AMOUNT) }
2209
2199
  - 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 }
2200
+ - COUPON_ISSUE: { couponId: string, integrationId: uuid }
2201
+ - BLOCK: { reason: string }
2211
2202
  - NOTIFICATION: { channel: "SMS"|"EMAIL"|"PUSH"|"KAKAO", targetVar: string, templateId: string, integrationId: uuid }
2212
2203
  - WEBHOOK: { url: string, method: "POST" }
2213
2204
  - SET_FACT: { key: string, value: string|number|boolean }
@@ -2241,7 +2232,7 @@ function registerRuleTools(server, callApi) {
2241
2232
  },
2242
2233
  async ({ groupId, versionId, ruleId, rule }) => {
2243
2234
  const body = JSON.parse(rule);
2244
- return callApi("PATCH", `policy-groups/${groupId}/versions/${versionId}/rules/${ruleId}`, {
2235
+ return callApi("PUT", `policy-groups/${groupId}/versions/${versionId}/rules/${ruleId}`, {
2245
2236
  body
2246
2237
  });
2247
2238
  }
@@ -2282,7 +2273,7 @@ function registerRuleTools(server, callApi) {
2282
2273
  ruleId,
2283
2274
  priority: index
2284
2275
  }));
2285
- return callApi("PUT", `policy-groups/${groupId}/versions/${versionId}/rules/reorder`, {
2276
+ return callApi("PATCH", `policy-groups/${groupId}/versions/${versionId}/rules/reorder`, {
2286
2277
  body: { rules }
2287
2278
  });
2288
2279
  }
@@ -2299,7 +2290,7 @@ function registerRuleTools(server, callApi) {
2299
2290
  isEnabled: z3.boolean().describe("true to enable, false to disable")
2300
2291
  }
2301
2292
  },
2302
- async ({ groupId, versionId, ruleId, isEnabled }) => callApi("PATCH", `policy-groups/${groupId}/versions/${versionId}/rules/${ruleId}/toggle`, {
2293
+ async ({ groupId, versionId, ruleId, isEnabled }) => callApi("PATCH", `policy-groups/${groupId}/versions/${versionId}/rules/${ruleId}/enabled`, {
2303
2294
  body: { isEnabled }
2304
2295
  })
2305
2296
  );
@@ -2352,7 +2343,7 @@ function registerFactTools(server, callApi) {
2352
2343
  isRequired: z4.boolean().describe("Required flag")
2353
2344
  }
2354
2345
  },
2355
- async ({ factId, ...body }) => callApi("PATCH", `schema/facts/${factId}`, { body })
2346
+ async ({ factId, ...body }) => callApi("PUT", `schema/facts/${factId}`, { body })
2356
2347
  );
2357
2348
  server.registerTool(
2358
2349
  "lexq_facts_delete",
@@ -2378,7 +2369,7 @@ function registerDeployTools(server, callApi) {
2378
2369
  inputSchema: {
2379
2370
  groupId: z5.string().uuid().describe("Policy group ID"),
2380
2371
  versionId: z5.string().uuid().describe("Version ID to publish"),
2381
- memo: z5.string().default("").describe("Deployment memo")
2372
+ memo: z5.string().min(1).describe("Publish Deployment memo (required)")
2382
2373
  }
2383
2374
  },
2384
2375
  async ({ groupId, versionId, memo }) => callApi("POST", `policy-groups/${groupId}/versions/${versionId}/publish`, { body: { memo } })
@@ -2391,7 +2382,7 @@ function registerDeployTools(server, callApi) {
2391
2382
  inputSchema: {
2392
2383
  groupId: z5.string().uuid().describe("Policy group ID"),
2393
2384
  versionId: z5.string().uuid().describe("Version ID to deploy"),
2394
- memo: z5.string().default("").describe("Deployment memo")
2385
+ memo: z5.string().min(1).describe("Live Deployment memo (required)")
2395
2386
  }
2396
2387
  },
2397
2388
  async ({ groupId, versionId, memo }) => callApi("POST", `policy-groups/${groupId}/deploy`, {
@@ -2475,10 +2466,8 @@ function registerAnalyticsTools(server, callApi) {
2475
2466
  {
2476
2467
  title: "Dry Run",
2477
2468
  description: `Execute a single dry run against a version. Tests how rules evaluate given input facts without side effects.
2478
-
2479
- Example input: { "facts": { "payment_amount": 100000, "customer_tier": "VIP" } }
2480
-
2481
- Always dry-run before publishing to validate rule behavior.`,
2469
+ Example input: { "facts": { "payment_amount": 100000, "customer_tier": "VIP" } }
2470
+ Always dry-run before publishing to validate rule behavior.`,
2482
2471
  inputSchema: {
2483
2472
  versionId: z6.string().uuid().describe("Policy version ID to test against"),
2484
2473
  facts: z6.string().describe('JSON string of facts object, e.g. {"payment_amount":100000}'),
@@ -2527,14 +2516,21 @@ Always dry-run before publishing to validate rule behavior.`,
2527
2516
  "lexq_simulation_start",
2528
2517
  {
2529
2518
  title: "Start Simulation",
2530
- description: `Start a batch simulation against historical execution data.
2531
-
2532
- Example body:
2533
- {
2534
- "policyVersionId": "<uuid>",
2535
- "dataset": { "type": "HISTORICAL", "source": "EXECUTION_LOGS", "from": "2025-01-01", "to": "2025-01-31" },
2536
- "options": { "baselinePolicyVersionId": "<uuid>", "includeRuleStats": true, "maxRecords": 10000 }
2537
- }`,
2519
+ description: `Start a batch simulation against historical or uploaded data.
2520
+
2521
+ dataset.type: "HISTORICAL" or "UPLOADED"
2522
+ dataset.source (when HISTORICAL): "EXECUTION_LOGS"
2523
+ dataset.from / dataset.to: date range (yyyy-MM-dd, when HISTORICAL)
2524
+ options.maxRecords: number (max 100000, default 10000)
2525
+ options.baselinePolicyVersionId: uuid (optional, for comparison)
2526
+ options.includeRuleStats: boolean
2527
+
2528
+ Example body:
2529
+ {
2530
+ "policyVersionId": "<uuid>",
2531
+ "dataset": { "type": "HISTORICAL", "source": "EXECUTION_LOGS", "from": "2025-01-01", "to": "2025-01-31" },
2532
+ "options": { "baselinePolicyVersionId": "<uuid>", "includeRuleStats": true, "maxRecords": 10000 }
2533
+ }`,
2538
2534
  inputSchema: {
2539
2535
  body: z6.string().describe("JSON string of SimulationRequest")
2540
2536
  }
@@ -2606,16 +2602,15 @@ Example body:
2606
2602
  {
2607
2603
  title: "Upload Dataset",
2608
2604
  description: `Upload inline CSV or JSON content as a simulation dataset.
2609
- The content is uploaded to S3 and a path is returned.
2610
- Use this path in simulation start with dataset type UPLOADED.
2611
-
2612
- CSV example:
2613
- user_id,payment_amount
2614
- user_001,150000
2615
- user_002,50000
2616
-
2617
- JSON example:
2618
- [{"user_id":"user_001","payment_amount":150000}, {"user_id":"user_002","payment_amount":50000}]`,
2605
+ The content is uploaded to S3 and a path is returned.
2606
+ Use this path in simulation start with dataset type UPLOADED.
2607
+
2608
+ CSV example:
2609
+ user_id,payment_amount
2610
+ user_001,150000
2611
+ user_002,50000
2612
+
2613
+ JSON example: [{"user_id":"user_001","payment_amount":150000}, {"user_id":"user_002","payment_amount":50000}]`,
2619
2614
  inputSchema: {
2620
2615
  content: z6.string().describe("CSV or JSON content as string"),
2621
2616
  filename: z6.string().default("dataset.csv").describe("Filename with extension (.csv or .json)")
@@ -2678,10 +2673,10 @@ function registerHistoryTools(server, callApi) {
2678
2673
  title: "Get Execution Detail",
2679
2674
  description: "Get full execution detail including request facts, result traces, and decision traces.",
2680
2675
  inputSchema: {
2681
- executionId: z7.string().uuid().describe("Execution history ID")
2676
+ traceId: z7.string().describe("Trace ID from execution history")
2682
2677
  }
2683
2678
  },
2684
- async ({ executionId }) => callApi("GET", `execution/history/${executionId}`)
2679
+ async ({ traceId }) => callApi("GET", `execution/history/${traceId}`)
2685
2680
  );
2686
2681
  server.registerTool(
2687
2682
  "lexq_history_stats",
@@ -2739,19 +2734,20 @@ function registerIntegrationTools(server, callApi) {
2739
2734
  "lexq_integrations_save",
2740
2735
  {
2741
2736
  title: "Save Integration",
2742
- description: "Create or update an integration. Types: COUPON, POINT, NOTIFICATION, CRM, MESSENGER, WEBHOOK.",
2737
+ description: "Create or update an integration. Provide id to update an existing one; omit id to create new. Types: COUPON, POINT, NOTIFICATION, CRM, MESSENGER, WEBHOOK.",
2743
2738
  inputSchema: {
2739
+ id: z8.string().uuid().optional().describe("Integration ID (omit to create, provide to update)"),
2744
2740
  type: z8.enum(["COUPON", "POINT", "NOTIFICATION", "CRM", "MESSENGER", "WEBHOOK"]).describe("Integration type"),
2745
2741
  name: z8.string().describe("Integration name"),
2746
2742
  baseUrl: z8.string().describe("Base URL of the external service"),
2747
- apiKey: z8.string().optional().describe("API key or token for the service"),
2748
- isActive: z8.boolean().default(true).describe("Whether the integration is active"),
2749
- config: z8.string().optional().describe("JSON string of additional config key-value pairs")
2743
+ credential: z8.string().optional().describe("API key or token for the service"),
2744
+ additionalConfig: z8.string().optional().describe("JSON string of additional config key-value pairs"),
2745
+ isActive: z8.boolean().default(true).describe("Whether the integration is active")
2750
2746
  }
2751
2747
  },
2752
- async ({ config, ...rest }) => {
2748
+ async ({ additionalConfig, ...rest }) => {
2753
2749
  const body = { ...rest };
2754
- if (config) body.config = JSON.parse(config);
2750
+ if (additionalConfig) body.additionalConfig = JSON.parse(additionalConfig);
2755
2751
  return callApi("POST", "integrations", { body });
2756
2752
  }
2757
2753
  );
@@ -35,18 +35,14 @@ function registerGroupTools(server, callApi) {
35
35
  "lexq_groups_list",
36
36
  {
37
37
  title: "List Policy Groups",
38
- description: "List all policy groups. Supports pagination and optional status/keyword filters.",
38
+ description: "List all policy groups with pagination.",
39
39
  inputSchema: {
40
40
  page: z.number().int().min(0).default(0).describe("Page number (0-indexed)"),
41
- size: z.number().int().min(1).max(100).default(20).describe("Page size"),
42
- status: z.enum(["ACTIVE", "DISABLED", "ARCHIVED"]).optional().describe("Filter by status"),
43
- keyword: z.string().optional().describe("Search keyword")
41
+ size: z.number().int().min(1).max(100).default(20).describe("Page size")
44
42
  }
45
43
  },
46
- async ({ page, size, status, keyword }) => {
44
+ async ({ page, size }) => {
47
45
  const params = paginationParams(page, size);
48
- if (status) params.status = status;
49
- if (keyword) params.keyword = keyword;
50
46
  return callApi("GET", "policy-groups", { params });
51
47
  }
52
48
  );
@@ -70,10 +66,10 @@ function registerGroupTools(server, callApi) {
70
66
  name: z.string().describe("Group name (unique among non-ARCHIVED)"),
71
67
  priority: z.number().int().min(0).describe("Execution priority (lower = higher)"),
72
68
  description: z.string().optional().describe("Group description"),
73
- conflictResolutionMode: z.enum(["NONE", "EXCLUSIVE", "MAX_N"]).optional().describe("Conflict resolution mode"),
74
- conflictResolutionStrategy: z.enum(["FIRST_MATCH", "HIGHEST_PRIORITY", "MAX_BENEFIT"]).optional().describe("Strategy when mode is EXCLUSIVE or MAX_N"),
75
- maxSelections: z.number().int().min(1).optional().describe("Max selections (required when mode is MAX_N)"),
76
- activationGroupId: z.string().uuid().optional().describe("Activation group ID")
69
+ activationMode: z.enum(["NONE", "EXCLUSIVE", "MAX_N"]).optional().describe("Conflict resolution mode"),
70
+ activationStrategy: z.enum(["FIRST_MATCH", "HIGHEST_PRIORITY", "MAX_BENEFIT"]).optional().describe("Strategy when mode is EXCLUSIVE or MAX_N"),
71
+ executionLimit: z.number().int().min(1).optional().describe("Max rule executions (required when mode is MAX_N)"),
72
+ activationGroup: z.string().optional().describe("Activation group name")
77
73
  }
78
74
  },
79
75
  async (args) => {
@@ -82,12 +78,10 @@ function registerGroupTools(server, callApi) {
82
78
  priority: args.priority
83
79
  };
84
80
  if (args.description !== void 0) body.description = args.description;
85
- if (args.conflictResolutionMode !== void 0)
86
- body.conflictResolutionMode = args.conflictResolutionMode;
87
- if (args.conflictResolutionStrategy !== void 0)
88
- body.conflictResolutionStrategy = args.conflictResolutionStrategy;
89
- if (args.maxSelections !== void 0) body.maxSelections = args.maxSelections;
90
- if (args.activationGroupId !== void 0) body.activationGroupId = args.activationGroupId;
81
+ if (args.activationMode !== void 0) body.activationMode = args.activationMode;
82
+ if (args.activationStrategy !== void 0) body.activationStrategy = args.activationStrategy;
83
+ if (args.executionLimit !== void 0) body.executionLimit = args.executionLimit;
84
+ if (args.activationGroup !== void 0) body.activationGroup = args.activationGroup;
91
85
  return callApi("POST", "policy-groups", { body });
92
86
  }
93
87
  );
@@ -95,19 +89,19 @@ function registerGroupTools(server, callApi) {
95
89
  "lexq_groups_update",
96
90
  {
97
91
  title: "Update Policy Group",
98
- description: "Update an existing policy group. Only provided fields are updated.",
92
+ description: "Update a policy group. This is a full replacement \u2014 omitted optional fields will be set to null on the server.",
99
93
  inputSchema: {
100
94
  groupId: z.string().uuid().describe("Policy group ID"),
101
95
  name: z.string().optional().describe("New name"),
102
96
  priority: z.number().int().min(0).optional().describe("New priority"),
103
97
  description: z.string().optional().describe("New description"),
104
98
  status: z.enum(["ACTIVE", "DISABLED"]).optional().describe("Status (DISABLED = emergency stop)"),
105
- conflictResolutionMode: z.enum(["NONE", "EXCLUSIVE", "MAX_N"]).optional().describe("Conflict resolution mode"),
106
- conflictResolutionStrategy: z.enum(["FIRST_MATCH", "HIGHEST_PRIORITY", "MAX_BENEFIT"]).optional().describe("Strategy"),
107
- maxSelections: z.number().int().min(1).optional().describe("Max selections")
99
+ activationMode: z.enum(["NONE", "EXCLUSIVE", "MAX_N"]).optional().describe("Conflict resolution mode"),
100
+ activationStrategy: z.enum(["FIRST_MATCH", "HIGHEST_PRIORITY", "MAX_BENEFIT"]).optional().describe("Strategy"),
101
+ executionLimit: z.number().int().min(1).optional().describe("Max rule executions")
108
102
  }
109
103
  },
110
- async ({ groupId, ...body }) => callApi("PATCH", `policy-groups/${groupId}`, { body })
104
+ async ({ groupId, ...body }) => callApi("PUT", `policy-groups/${groupId}`, { body })
111
105
  );
112
106
  server.registerTool(
113
107
  "lexq_groups_delete",
@@ -124,41 +118,37 @@ function registerGroupTools(server, callApi) {
124
118
  "lexq_ab_test_start",
125
119
  {
126
120
  title: "Start A/B Test",
127
- description: "Start an A/B test on a policy group. Requires a challenger version ID and traffic split percentages.",
121
+ description: "Start an A/B test on a policy group. Requires a challenger version ID and traffic rate.",
128
122
  inputSchema: {
129
123
  groupId: z.string().uuid().describe("Policy group ID"),
130
- challengerVersionId: z.string().uuid().describe("Challenger version ID"),
131
- controlWeight: z.number().int().min(1).max(99).describe("Control traffic weight (%)"),
132
- challengerWeight: z.number().int().min(1).max(99).describe("Challenger traffic weight (%)"),
133
- identityKey: z.string().optional().describe("Fact key for sticky assignment (e.g. customer_id)")
124
+ testVersionId: z.string().uuid().describe("Challenger version ID to test"),
125
+ trafficRate: z.number().int().min(1).max(99).describe("Traffic percentage routed to challenger (1-99)")
134
126
  }
135
127
  },
136
- async ({ groupId, ...body }) => callApi("POST", `policy-groups/${groupId}/ab-test/start`, { body })
128
+ async ({ groupId, ...body }) => callApi("POST", `policy-groups/${groupId}/ab-test`, { body })
137
129
  );
138
130
  server.registerTool(
139
131
  "lexq_ab_test_stop",
140
132
  {
141
133
  title: "Stop A/B Test",
142
- description: "Stop a running A/B test. Specify which version to keep.",
134
+ description: "Stop a running A/B test. All traffic is restored to the control (current) version.",
143
135
  inputSchema: {
144
- groupId: z.string().uuid().describe("Policy group ID"),
145
- winnerVersionId: z.string().uuid().describe("Version ID to keep as live")
136
+ groupId: z.string().uuid().describe("Policy group ID")
146
137
  }
147
138
  },
148
- async ({ groupId, ...body }) => callApi("POST", `policy-groups/${groupId}/ab-test/stop`, { body })
139
+ async ({ groupId }) => callApi("DELETE", `policy-groups/${groupId}/ab-test`)
149
140
  );
150
141
  server.registerTool(
151
142
  "lexq_ab_test_adjust",
152
143
  {
153
144
  title: "Adjust A/B Test",
154
- description: "Adjust traffic weights of a running A/B test.",
145
+ description: "Adjust traffic rate of a running A/B test.",
155
146
  inputSchema: {
156
147
  groupId: z.string().uuid().describe("Policy group ID"),
157
- controlWeight: z.number().int().min(1).max(99).describe("New control weight (%)"),
158
- challengerWeight: z.number().int().min(1).max(99).describe("New challenger weight (%)")
148
+ trafficRate: z.number().int().min(1).max(99).describe("New traffic percentage for challenger (1-99)")
159
149
  }
160
150
  },
161
- async ({ groupId, ...body }) => callApi("POST", `policy-groups/${groupId}/ab-test/adjust`, { body })
151
+ async ({ groupId, ...body }) => callApi("PATCH", `policy-groups/${groupId}/ab-test/traffic-rate`, { body })
162
152
  );
163
153
  }
164
154
 
@@ -219,7 +209,7 @@ function registerVersionTools(server, callApi) {
219
209
  effectiveTo: z2.string().optional().describe("New effective end date")
220
210
  }
221
211
  },
222
- async ({ groupId, versionId, ...body }) => callApi("PATCH", `policy-groups/${groupId}/versions/${versionId}`, { body })
212
+ async ({ groupId, versionId, ...body }) => callApi("PUT", `policy-groups/${groupId}/versions/${versionId}`, { body })
223
213
  );
224
214
  server.registerTool(
225
215
  "lexq_versions_delete",
@@ -240,15 +230,12 @@ function registerVersionTools(server, callApi) {
240
230
  description: "Clone an existing version to create a new DRAFT. Useful when the source version is already published.",
241
231
  inputSchema: {
242
232
  groupId: z2.string().uuid().describe("Policy group ID"),
243
- versionId: z2.string().uuid().describe("Source version ID to clone"),
244
- commitMessage: z2.string().optional().describe("Commit message for the cloned version")
233
+ versionId: z2.string().uuid().describe("Source version ID to clone")
245
234
  }
246
235
  },
247
- async ({ groupId, versionId, commitMessage }) => {
248
- const body = {};
249
- if (commitMessage !== void 0) body.commitMessage = commitMessage;
236
+ async ({ groupId, versionId }) => {
250
237
  return callApi("POST", `policy-groups/${groupId}/versions/${versionId}/clone`, {
251
- body
238
+ body: {}
252
239
  });
253
240
  }
254
241
  );
@@ -290,17 +277,21 @@ function registerRuleTools(server, callApi) {
290
277
  "lexq_rules_create",
291
278
  {
292
279
  title: "Create Rule",
293
- description: `Create a rule in a DRAFT version. Requires name, priority, condition tree, and actions array.
280
+ description: `Create a rule in a DRAFT version. Requires name, priority, condition tree, and actions array.
281
+
282
+ Note: Rules can reference fact keys that are not yet registered in Fact Definitions. The engine allows this for flexibility. However, registering facts via lexq_facts_create is recommended \u2014 it enables type validation, the Console UI autocomplete, and the dry-run requirements analyzer.
283
+
294
284
  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
285
+ Operators: EQUALS, NOT_EQUALS, GREATER_THAN, GREATER_THAN_OR_EQUAL, LESS_THAN, LESS_THAN_OR_EQUAL, CONTAINS, IN, NOT_IN
296
286
  Value types: STRING, NUMBER, BOOLEAN, LIST_STRING, LIST_NUMBER
297
-
287
+
298
288
  Actions: [{ type, parameters }]
299
-
289
+
300
290
  Action parameter schemas:
301
- - DISCOUNT: { refVar: string, method: "PERCENTAGE"|"AMOUNT", rate: number }
291
+ - DISCOUNT: { refVar: string, method: "PERCENTAGE"|"AMOUNT", rate?: number (when PERCENTAGE), value?: number (when AMOUNT) }
302
292
  - 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 }
293
+ - COUPON_ISSUE: { couponId: string, integrationId: uuid }
294
+ - BLOCK: { reason: string }
304
295
  - NOTIFICATION: { channel: "SMS"|"EMAIL"|"PUSH"|"KAKAO", targetVar: string, templateId: string, integrationId: uuid }
305
296
  - WEBHOOK: { url: string, method: "POST" }
306
297
  - SET_FACT: { key: string, value: string|number|boolean }
@@ -334,7 +325,7 @@ function registerRuleTools(server, callApi) {
334
325
  },
335
326
  async ({ groupId, versionId, ruleId, rule }) => {
336
327
  const body = JSON.parse(rule);
337
- return callApi("PATCH", `policy-groups/${groupId}/versions/${versionId}/rules/${ruleId}`, {
328
+ return callApi("PUT", `policy-groups/${groupId}/versions/${versionId}/rules/${ruleId}`, {
338
329
  body
339
330
  });
340
331
  }
@@ -375,7 +366,7 @@ function registerRuleTools(server, callApi) {
375
366
  ruleId,
376
367
  priority: index
377
368
  }));
378
- return callApi("PUT", `policy-groups/${groupId}/versions/${versionId}/rules/reorder`, {
369
+ return callApi("PATCH", `policy-groups/${groupId}/versions/${versionId}/rules/reorder`, {
379
370
  body: { rules }
380
371
  });
381
372
  }
@@ -392,7 +383,7 @@ function registerRuleTools(server, callApi) {
392
383
  isEnabled: z3.boolean().describe("true to enable, false to disable")
393
384
  }
394
385
  },
395
- async ({ groupId, versionId, ruleId, isEnabled }) => callApi("PATCH", `policy-groups/${groupId}/versions/${versionId}/rules/${ruleId}/toggle`, {
386
+ async ({ groupId, versionId, ruleId, isEnabled }) => callApi("PATCH", `policy-groups/${groupId}/versions/${versionId}/rules/${ruleId}/enabled`, {
396
387
  body: { isEnabled }
397
388
  })
398
389
  );
@@ -445,7 +436,7 @@ function registerFactTools(server, callApi) {
445
436
  isRequired: z4.boolean().describe("Required flag")
446
437
  }
447
438
  },
448
- async ({ factId, ...body }) => callApi("PATCH", `schema/facts/${factId}`, { body })
439
+ async ({ factId, ...body }) => callApi("PUT", `schema/facts/${factId}`, { body })
449
440
  );
450
441
  server.registerTool(
451
442
  "lexq_facts_delete",
@@ -471,7 +462,7 @@ function registerDeployTools(server, callApi) {
471
462
  inputSchema: {
472
463
  groupId: z5.string().uuid().describe("Policy group ID"),
473
464
  versionId: z5.string().uuid().describe("Version ID to publish"),
474
- memo: z5.string().default("").describe("Deployment memo")
465
+ memo: z5.string().min(1).describe("Publish Deployment memo (required)")
475
466
  }
476
467
  },
477
468
  async ({ groupId, versionId, memo }) => callApi("POST", `policy-groups/${groupId}/versions/${versionId}/publish`, { body: { memo } })
@@ -484,7 +475,7 @@ function registerDeployTools(server, callApi) {
484
475
  inputSchema: {
485
476
  groupId: z5.string().uuid().describe("Policy group ID"),
486
477
  versionId: z5.string().uuid().describe("Version ID to deploy"),
487
- memo: z5.string().default("").describe("Deployment memo")
478
+ memo: z5.string().min(1).describe("Live Deployment memo (required)")
488
479
  }
489
480
  },
490
481
  async ({ groupId, versionId, memo }) => callApi("POST", `policy-groups/${groupId}/deploy`, {
@@ -568,10 +559,8 @@ function registerAnalyticsTools(server, callApi) {
568
559
  {
569
560
  title: "Dry Run",
570
561
  description: `Execute a single dry run against a version. Tests how rules evaluate given input facts without side effects.
571
-
572
- Example input: { "facts": { "payment_amount": 100000, "customer_tier": "VIP" } }
573
-
574
- Always dry-run before publishing to validate rule behavior.`,
562
+ Example input: { "facts": { "payment_amount": 100000, "customer_tier": "VIP" } }
563
+ Always dry-run before publishing to validate rule behavior.`,
575
564
  inputSchema: {
576
565
  versionId: z6.string().uuid().describe("Policy version ID to test against"),
577
566
  facts: z6.string().describe('JSON string of facts object, e.g. {"payment_amount":100000}'),
@@ -620,14 +609,21 @@ Always dry-run before publishing to validate rule behavior.`,
620
609
  "lexq_simulation_start",
621
610
  {
622
611
  title: "Start Simulation",
623
- description: `Start a batch simulation against historical execution data.
624
-
625
- Example body:
626
- {
627
- "policyVersionId": "<uuid>",
628
- "dataset": { "type": "HISTORICAL", "source": "EXECUTION_LOGS", "from": "2025-01-01", "to": "2025-01-31" },
629
- "options": { "baselinePolicyVersionId": "<uuid>", "includeRuleStats": true, "maxRecords": 10000 }
630
- }`,
612
+ description: `Start a batch simulation against historical or uploaded data.
613
+
614
+ dataset.type: "HISTORICAL" or "UPLOADED"
615
+ dataset.source (when HISTORICAL): "EXECUTION_LOGS"
616
+ dataset.from / dataset.to: date range (yyyy-MM-dd, when HISTORICAL)
617
+ options.maxRecords: number (max 100000, default 10000)
618
+ options.baselinePolicyVersionId: uuid (optional, for comparison)
619
+ options.includeRuleStats: boolean
620
+
621
+ Example body:
622
+ {
623
+ "policyVersionId": "<uuid>",
624
+ "dataset": { "type": "HISTORICAL", "source": "EXECUTION_LOGS", "from": "2025-01-01", "to": "2025-01-31" },
625
+ "options": { "baselinePolicyVersionId": "<uuid>", "includeRuleStats": true, "maxRecords": 10000 }
626
+ }`,
631
627
  inputSchema: {
632
628
  body: z6.string().describe("JSON string of SimulationRequest")
633
629
  }
@@ -699,16 +695,15 @@ Example body:
699
695
  {
700
696
  title: "Upload Dataset",
701
697
  description: `Upload inline CSV or JSON content as a simulation dataset.
702
- The content is uploaded to S3 and a path is returned.
703
- Use this path in simulation start with dataset type UPLOADED.
704
-
705
- CSV example:
706
- user_id,payment_amount
707
- user_001,150000
708
- user_002,50000
709
-
710
- JSON example:
711
- [{"user_id":"user_001","payment_amount":150000}, {"user_id":"user_002","payment_amount":50000}]`,
698
+ The content is uploaded to S3 and a path is returned.
699
+ Use this path in simulation start with dataset type UPLOADED.
700
+
701
+ CSV example:
702
+ user_id,payment_amount
703
+ user_001,150000
704
+ user_002,50000
705
+
706
+ JSON example: [{"user_id":"user_001","payment_amount":150000}, {"user_id":"user_002","payment_amount":50000}]`,
712
707
  inputSchema: {
713
708
  content: z6.string().describe("CSV or JSON content as string"),
714
709
  filename: z6.string().default("dataset.csv").describe("Filename with extension (.csv or .json)")
@@ -771,10 +766,10 @@ function registerHistoryTools(server, callApi) {
771
766
  title: "Get Execution Detail",
772
767
  description: "Get full execution detail including request facts, result traces, and decision traces.",
773
768
  inputSchema: {
774
- executionId: z7.string().uuid().describe("Execution history ID")
769
+ traceId: z7.string().describe("Trace ID from execution history")
775
770
  }
776
771
  },
777
- async ({ executionId }) => callApi("GET", `execution/history/${executionId}`)
772
+ async ({ traceId }) => callApi("GET", `execution/history/${traceId}`)
778
773
  );
779
774
  server.registerTool(
780
775
  "lexq_history_stats",
@@ -832,19 +827,20 @@ function registerIntegrationTools(server, callApi) {
832
827
  "lexq_integrations_save",
833
828
  {
834
829
  title: "Save Integration",
835
- description: "Create or update an integration. Types: COUPON, POINT, NOTIFICATION, CRM, MESSENGER, WEBHOOK.",
830
+ description: "Create or update an integration. Provide id to update an existing one; omit id to create new. Types: COUPON, POINT, NOTIFICATION, CRM, MESSENGER, WEBHOOK.",
836
831
  inputSchema: {
832
+ id: z8.string().uuid().optional().describe("Integration ID (omit to create, provide to update)"),
837
833
  type: z8.enum(["COUPON", "POINT", "NOTIFICATION", "CRM", "MESSENGER", "WEBHOOK"]).describe("Integration type"),
838
834
  name: z8.string().describe("Integration name"),
839
835
  baseUrl: z8.string().describe("Base URL of the external service"),
840
- apiKey: z8.string().optional().describe("API key or token for the service"),
841
- isActive: z8.boolean().default(true).describe("Whether the integration is active"),
842
- config: z8.string().optional().describe("JSON string of additional config key-value pairs")
836
+ credential: z8.string().optional().describe("API key or token for the service"),
837
+ additionalConfig: z8.string().optional().describe("JSON string of additional config key-value pairs"),
838
+ isActive: z8.boolean().default(true).describe("Whether the integration is active")
843
839
  }
844
840
  },
845
- async ({ config, ...rest }) => {
841
+ async ({ additionalConfig, ...rest }) => {
846
842
  const body = { ...rest };
847
- if (config) body.config = JSON.parse(config);
843
+ if (additionalConfig) body.additionalConfig = JSON.parse(additionalConfig);
848
844
  return callApi("POST", "integrations", { body });
849
845
  }
850
846
  );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lexq/cli",
3
- "version": "0.1.13",
3
+ "version": "0.1.15",
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": {