@lexq/cli 0.1.40 → 0.1.42

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
@@ -389,7 +389,7 @@ ${data.length} total`);
389
389
  description string Description (optional, max 255 chars)
390
390
  activationGroup string Execution Group — conflict-resolution cluster key (optional)
391
391
  activationMode string NONE | EXCLUSIVE | MAX_N [default: NONE]
392
- activationStrategy string FIRST_MATCH | HIGHEST_PRIORITY | MAX_BENEFIT [default: FIRST_MATCH]
392
+ activationStrategy string HIGHEST_PRIORITY [default, and currently the only value]
393
393
  executionLimit number Max rules to fire in MAX_N mode (optional)
394
394
  status string ACTIVE | DISABLED [default: ACTIVE]
395
395
 
@@ -929,7 +929,7 @@ ${data.length} total`);
929
929
  "valueType": "STRING"
930
930
  },
931
931
  "actions": [
932
- { "type": "MUTATE_FACT", "parameters": { "refVar": "payment_amount", "operator": "SUB", "method": "PERCENTAGE", "rate": 20 } }
932
+ { "type": "MUTATE_FACT", "parameters": { "targetVar": "payment_amount", "operator": "SUB", "method": "PERCENTAGE", "operand": 20 } }
933
933
  ]
934
934
  }'
935
935
 
@@ -956,14 +956,19 @@ ${data.length} total`);
956
956
  IN is the mirror of HAS_*: scalar fact, list value.
957
957
 
958
958
  Action Types:
959
- MUTATE_FACT, INCREMENT_FACT, EMIT_EVENT, BLOCK, EMIT_NOTIFICATION, EMIT_WEBHOOK, SET_FACT, ADD_TAG
959
+ MUTATE_FACT { targetVar, operator, method, operand, refVar?, rounding? }
960
+ SET_FACT { targetVar, value }
961
+ BLOCK { reason }
962
+
963
+ refVar is the percentage base and is optional — omit to use targetVar itself.
964
+ It is only valid in PERCENTAGE × {ASSIGN, ADD, SUB}.
960
965
 
961
966
  Value Types: STRING, NUMBER, BOOLEAN, LIST_STRING, LIST_NUMBER
962
967
 
963
968
  Mutex (optional — rule-level conflict resolution):
964
969
  mutexGroup string Logical grouping key (e.g., "best-discount")
965
970
  mutexMode string NONE | EXCLUSIVE | MAX_N [default: NONE]
966
- mutexStrategy string FIRST_MATCH | HIGHEST_PRIORITY | MAX_BENEFIT
971
+ mutexStrategy string HIGHEST_PRIORITY (currently the only value)
967
972
  mutexLimit number Max rules to fire in MAX_N mode (required when MAX_N)
968
973
 
969
974
  priority is auto-assigned (appended last). Use 'lexq rules reorder' to change order.
@@ -1000,7 +1005,7 @@ ${data.length} total`);
1000
1005
  $ lexq rules update --group-id <gid> --version-id <vid> --id <rid> --json '{
1001
1006
  "name": "VIP 25% Discount",
1002
1007
  "actions": [
1003
- { "type": "MUTATE_FACT", "parameters": { "refVar": "payment_amount", "operator": "SUB", "method": "PERCENTAGE", "rate": 25 } }
1008
+ { "type": "MUTATE_FACT", "parameters": { "targetVar": "payment_amount", "operator": "SUB", "method": "PERCENTAGE", "operand": 25 } }
1004
1009
  ]
1005
1010
  }'
1006
1011
  `
@@ -1826,18 +1831,17 @@ function registerAnalyticsCommands(program) {
1826
1831
  Workflow: facts check → dry-run → publish → simulation → deploy
1827
1832
  `
1828
1833
  );
1829
- analytics.command("dry-run").description("Execute a single dry run against a version").requiredOption("--version-id <versionId>", "Policy version ID").option("--json <body>", "Request body as JSON string").option("--file <path>", "Read request body from a JSON file").option("--debug", "Include debug traces", false).option("--mock", "Mock external calls", false).addHelpText(
1834
+ analytics.command("dry-run").description("Execute a single dry run against a version").requiredOption("--version-id <versionId>", "Policy version ID").option("--json <body>", "Request body as JSON string").option("--file <path>", "Read request body from a JSON file").option("--debug", "Include debug traces", false).addHelpText(
1830
1835
  "after",
1831
1836
  dedent8`
1832
1837
 
1833
1838
  Examples:
1834
- $ lexq analytics dry-run --version-id <vid> --debug --mock \\
1839
+ $ lexq analytics dry-run --version-id <vid> --debug \\
1835
1840
  --json '{"facts": {"payment_amount": 150000, "customer_tier": "VIP"}}'
1836
1841
 
1837
1842
  $ lexq analytics dry-run --version-id <vid> --file test-input.json
1838
1843
 
1839
1844
  The request body must include a "facts" object. Use --debug for execution traces
1840
- and --mock to skip external service calls (webhooks, coupons, etc.).
1841
1845
  `
1842
1846
  ).action(async (opts) => {
1843
1847
  try {
@@ -1847,7 +1851,6 @@ function registerAnalyticsCommands(program) {
1847
1851
  throw new Error('Request body must include "facts". Use --json or --file.');
1848
1852
  }
1849
1853
  body.includeDebugInfo = opts.debug;
1850
- body.mockExternalCalls = opts.mock;
1851
1854
  const data = await apiRequest(
1852
1855
  "POST",
1853
1856
  `analytics/dry-run/versions/${opts.versionId}`,
@@ -1957,7 +1960,7 @@ function registerAnalyticsCommands(program) {
1957
1960
  cancel Cancel a running simulation
1958
1961
  export Export results as CSV or JSON
1959
1962
 
1960
- Simulations always mock external calls. Use --format table for summary view.
1963
+ Use --format table for summary view.
1961
1964
  `
1962
1965
  );
1963
1966
  sim.command("start").description("Start a new batch simulation").requiredOption("--json <body>", "Simulation request body as JSON").option("--file <path>", "Read request body from a JSON file").addHelpText(
@@ -2319,27 +2322,12 @@ import "commander";
2319
2322
  import dedent9 from "dedent";
2320
2323
 
2321
2324
  // src/types/enums.ts
2325
+ var ConflictResolutionMode = ["NONE", "EXCLUSIVE", "MAX_N"];
2326
+ var ConflictResolutionStrategy = ["HIGHEST_PRIORITY"];
2322
2327
  var ProfileCacheState = ["HIT", "MISS"];
2323
2328
  var FailureStatus = ["PENDING", "RESOLVED", "IGNORED"];
2324
- var FailureAction = ["RETRY", "IGNORE", "RESOLVE"];
2325
- var TaskCategory = ["INTEGRATION", "INTERNAL"];
2326
- var TaskType = [
2327
- // Integration
2328
- "COUPON_ISSUE",
2329
- "COUPON_CANCEL",
2330
- "POINT_EARN",
2331
- "POINT_USE",
2332
- "POINT_REFUND",
2333
- "NOTIFICATION_SEND",
2334
- "CRM_SYNC_USER",
2335
- "CRM_ADD_TAG",
2336
- "WEBHOOK_EXECUTE",
2337
- // Internal
2338
- "IMAGE_PROCESSING",
2339
- "DAILY_SETTLEMENT",
2340
- "PLATFORM_WEBHOOK",
2341
- "SCHEDULED_DEPLOYMENT"
2342
- ];
2329
+ var FailureAction = ["IGNORE", "RESOLVE"];
2330
+ var TaskType = ["PLATFORM_WEBHOOK", "SCHEDULED_DEPLOYMENT"];
2343
2331
  var PlatformEventType = [
2344
2332
  "VERSION_PUBLISHED",
2345
2333
  "DEPLOYED",
@@ -2609,7 +2597,7 @@ function registerReplayCommands(program) {
2609
2597
  get Poll a job's status, summary, and changed samples
2610
2598
  cancel Cancel a PENDING/RUNNING job
2611
2599
 
2612
- External effects (webhooks, notifications) are always mocked during replay.
2600
+ A replay sends no webhook, notification, or event: rule actions produce no outward effects.
2613
2601
  `
2614
2602
  );
2615
2603
  replay.command("decision").description("Replay a single execution against a candidate version").requiredOption("--trace-id <traceId>", "Trace ID of the past execution").requiredOption("--version-id <versionId>", "Candidate version to re-evaluate against").addHelpText(
@@ -2819,216 +2807,32 @@ ${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
2819
2807
  });
2820
2808
  }
2821
2809
 
2822
- // src/commands/integrations.ts
2823
- import "commander";
2824
- import dedent13 from "dedent";
2825
- function registerIntegrationCommands(program) {
2826
- const integrations = program.command("integrations").description("Manage external integrations").addHelpText(
2827
- "after",
2828
- dedent13`
2829
-
2830
- Integrations connect rule actions to external services (webhooks, coupons,
2831
- points, notifications, CRM, messengers).
2832
-
2833
- Commands:
2834
- list List all integrations
2835
- get Get integration detail
2836
- save Create or update an integration
2837
- delete Delete an integration
2838
- config-spec Show required configuration fields per type
2839
-
2840
- Types: COUPON, POINT, NOTIFICATION, CRM, MESSENGER, WEBHOOK
2841
- `
2842
- );
2843
- integrations.command("list").description("List integrations").option(
2844
- "--type <type>",
2845
- "Filter by type (COUPON, POINT, NOTIFICATION, CRM, MESSENGER, WEBHOOK)"
2846
- ).option("--page <number>", "Page number", "0").option("--size <number>", "Page size", "20").action(async (opts) => {
2847
- try {
2848
- const globalOpts = program.opts();
2849
- const format = globalOpts.format ?? "json";
2850
- const params = { page: opts.page, size: opts.size };
2851
- if (opts.type) params.type = opts.type;
2852
- const data = await apiRequest("GET", "integrations", {
2853
- apiKey: globalOpts.apiKey,
2854
- baseUrl: globalOpts.baseUrl,
2855
- dryRun: globalOpts.dryRun,
2856
- verbose: globalOpts.verbose,
2857
- params
2858
- });
2859
- if (format === "table") {
2860
- printTable(
2861
- ["ID", "Name", "Type", "URL", "Active"],
2862
- data.content.map((i) => [
2863
- i.id.substring(0, 8),
2864
- i.name,
2865
- i.type,
2866
- i.baseUrl,
2867
- i.isActive ? "\u2713" : "\u2717"
2868
- ]),
2869
- { truncate: 28 }
2870
- );
2871
- console.log(`
2872
- ${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
2873
- } else {
2874
- printJson(data);
2875
- }
2876
- } catch (error) {
2877
- printError(error);
2878
- process.exit(1);
2879
- }
2880
- });
2881
- integrations.command("get").description("Get integration detail").requiredOption("--id <integrationId>", "Integration ID").action(async (opts) => {
2882
- try {
2883
- const globalOpts = program.opts();
2884
- const data = await apiRequest("GET", `integrations/${opts.id}`, {
2885
- apiKey: globalOpts.apiKey,
2886
- baseUrl: globalOpts.baseUrl,
2887
- dryRun: globalOpts.dryRun,
2888
- verbose: globalOpts.verbose
2889
- });
2890
- printJson(data);
2891
- } catch (error) {
2892
- printError(error);
2893
- process.exit(1);
2894
- }
2895
- });
2896
- integrations.command("save").description("Create or update an integration").requiredOption("--json <body>", "Request body as JSON string").addHelpText(
2897
- "after",
2898
- dedent13`
2899
-
2900
- Examples:
2901
- # Create
2902
- $ lexq integrations save --json '{
2903
- "type": "WEBHOOK",
2904
- "name": "Order Processing",
2905
- "baseUrl": "https://api.example.com/webhooks/orders",
2906
- "isActive": true
2907
- }'
2908
-
2909
- # Update (provide id)
2910
- $ lexq integrations save --json '{
2911
- "id": "<existing-id>",
2912
- "type": "WEBHOOK",
2913
- "name": "Order Processing (v2)",
2914
- "baseUrl": "https://api.example.com/v2/webhooks/orders",
2915
- "isActive": true
2916
- }'
2917
-
2918
- Fields:
2919
- id string Provide to update, omit to create
2920
- type string COUPON | POINT | NOTIFICATION | CRM | MESSENGER | WEBHOOK (required)
2921
- name string Integration name (required, unique per tenant)
2922
- baseUrl string Base URL of the external service (required)
2923
- credential string API key or token (optional, write-only)
2924
- additionalConfig object Extra config key-value pairs (optional)
2925
- isActive boolean Enable/disable [default: true]
2926
-
2927
- Use "lexq integrations config-spec" to see required fields per type.
2928
- `
2929
- ).action(async (opts) => {
2930
- try {
2931
- const globalOpts = program.opts();
2932
- const body = JSON.parse(opts.json);
2933
- const data = await apiRequest("POST", "integrations", {
2934
- apiKey: globalOpts.apiKey,
2935
- baseUrl: globalOpts.baseUrl,
2936
- dryRun: globalOpts.dryRun,
2937
- verbose: globalOpts.verbose,
2938
- body
2939
- });
2940
- printJson(data);
2941
- } catch (error) {
2942
- printError(error);
2943
- process.exit(1);
2944
- }
2945
- });
2946
- integrations.command("delete").description("Delete an integration").requiredOption("--id <integrationId>", "Integration ID").option("--force", "Skip confirmation prompt").addHelpText(
2947
- "after",
2948
- dedent13`
2949
-
2950
- Rules referencing this integration will fail at execution time.
2951
- Use --force to skip confirmation.
2952
- `
2953
- ).action(async (opts) => {
2954
- try {
2955
- const globalOpts = program.opts();
2956
- if (!opts.force) {
2957
- const { createInterface: createInterface2 } = await import("readline/promises");
2958
- const rl = createInterface2({ input: process.stdin, output: process.stdout });
2959
- const answer = await rl.question(`Delete integration ${opts.id}? [y/N] `);
2960
- rl.close();
2961
- if (answer.toLowerCase() !== "y") {
2962
- console.log("Canceled.");
2963
- return;
2964
- }
2965
- }
2966
- await apiRequest("DELETE", `integrations/${opts.id}`, {
2967
- apiKey: globalOpts.apiKey,
2968
- baseUrl: globalOpts.baseUrl,
2969
- dryRun: globalOpts.dryRun,
2970
- verbose: globalOpts.verbose
2971
- });
2972
- console.log(`\u2713 Integration ${opts.id} deleted.`);
2973
- } catch (error) {
2974
- printError(error);
2975
- process.exit(1);
2976
- }
2977
- });
2978
- integrations.command("config-spec").description("Get integration configuration field specs").addHelpText(
2979
- "after",
2980
- dedent13`
2981
-
2982
- Shows required and optional configuration fields for each integration type.
2983
-
2984
- Example:
2985
- $ lexq integrations config-spec
2986
- `
2987
- ).action(async () => {
2988
- try {
2989
- const globalOpts = program.opts();
2990
- const data = await apiRequest("GET", "integrations/config-spec", {
2991
- apiKey: globalOpts.apiKey,
2992
- baseUrl: globalOpts.baseUrl,
2993
- dryRun: globalOpts.dryRun,
2994
- verbose: globalOpts.verbose
2995
- });
2996
- printJson(data);
2997
- } catch (error) {
2998
- printError(error);
2999
- process.exit(1);
3000
- }
3001
- });
3002
- }
3003
-
3004
2810
  // src/commands/logs.ts
3005
2811
  import "commander";
3006
- import dedent14 from "dedent";
2812
+ import dedent13 from "dedent";
3007
2813
  function registerLogCommands(program) {
3008
2814
  const logs = program.command("logs").description("Failure logs").addHelpText(
3009
2815
  "after",
3010
- dedent14`
2816
+ dedent13`
3011
2817
 
3012
- System failure logs (DLQ) for background tasks — webhook calls, coupon issuance,
3013
- point operations, notifications, and platform event webhooks.
2818
+ System failure logs (DLQ) for background tasks — platform event webhooks and scheduled deployments.
3014
2819
 
3015
2820
  Commands:
3016
2821
  list List failure logs with filters
3017
- get Get failure log detail (includes payload for retry)
3018
- action Process a single log (RETRY, IGNORE, RESOLVE)
2822
+ get Get failure log detail (includes the original payload)
2823
+ action Process a single log (IGNORE, RESOLVE)
3019
2824
  bulk-action Process multiple logs at once
3020
2825
 
3021
2826
  Statuses: PENDING (needs attention), RESOLVED, IGNORED
3022
- Categories: INTEGRATION (external), INTERNAL (system)
3023
2827
  `
3024
2828
  );
3025
- logs.command("list").description("List failure logs").option("--category <category>", "Filter by category (INTEGRATION, INTERNAL)").option("--task-type <taskType>", `Filter by task type (${TaskType.join(", ")})`).option("--status <status>", "Filter by status (PENDING, RESOLVED, IGNORED)").option("--keyword <keyword>", "Search keyword").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").addHelpText(
2829
+ logs.command("list").description("List failure logs").option("--task-type <taskType>", `Filter by task type (${TaskType.join(", ")})`).option("--status <status>", "Filter by status (PENDING, RESOLVED, IGNORED)").option("--keyword <keyword>", "Search keyword").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").addHelpText(
3026
2830
  "after",
3027
- dedent14`
2831
+ dedent13`
3028
2832
 
3029
2833
  Examples:
3030
2834
  $ lexq logs list --status PENDING --format table
3031
- $ lexq logs list --task-type PLATFORM_WEBHOOK --category INTERNAL
2835
+ $ lexq logs list --task-type PLATFORM_WEBHOOK
3032
2836
  $ lexq logs list --keyword "timeout" --start-date 2026-04-01
3033
2837
  `
3034
2838
  ).action(async (opts) => {
@@ -3036,7 +2840,6 @@ function registerLogCommands(program) {
3036
2840
  const globalOpts = program.opts();
3037
2841
  const format = globalOpts.format ?? "json";
3038
2842
  const params = { page: opts.page, size: opts.size };
3039
- if (opts.category) params.category = opts.category;
3040
2843
  if (opts.taskType) params.taskType = opts.taskType;
3041
2844
  if (opts.status) params.status = opts.status;
3042
2845
  if (opts.keyword) params.searchKeyword = opts.keyword;
@@ -3051,13 +2854,11 @@ function registerLogCommands(program) {
3051
2854
  });
3052
2855
  if (format === "table") {
3053
2856
  printTable(
3054
- ["ID", "Category", "Task", "Status", "Retries", "Error", "Created"],
2857
+ ["ID", "Task", "Status", "Error", "Created"],
3055
2858
  data.content.map((l) => [
3056
2859
  l.id.substring(0, 8),
3057
- l.category,
3058
2860
  l.taskType,
3059
2861
  l.status,
3060
- String(l.retryCount),
3061
2862
  l.errorMessage?.substring(0, 24) ?? "\u2013",
3062
2863
  l.createdAt.substring(0, 16)
3063
2864
  ]),
@@ -3075,10 +2876,10 @@ ${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
3075
2876
  });
3076
2877
  logs.command("get").description("Get failure log detail").requiredOption("--id <logId>", "Log ID").addHelpText(
3077
2878
  "after",
3078
- dedent14`
2879
+ dedent13`
3079
2880
 
3080
2881
  Includes the full payload that was used for the failed operation.
3081
- Use this to inspect what went wrong before deciding to RETRY or RESOLVE.
2882
+ Use this to inspect what went wrong before deciding to IGNORE or RESOLVE.
3082
2883
  `
3083
2884
  ).action(async (opts) => {
3084
2885
  try {
@@ -3095,17 +2896,16 @@ ${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
3095
2896
  process.exit(1);
3096
2897
  }
3097
2898
  });
3098
- logs.command("action").description("Process a failure log action (RETRY, IGNORE, RESOLVE)").requiredOption("--id <logId>", "Log ID").requiredOption("--action <action>", "Action: RETRY, IGNORE, or RESOLVE").addHelpText(
2899
+ logs.command("action").description("Process a failure log action (IGNORE, RESOLVE)").requiredOption("--id <logId>", "Log ID").requiredOption("--action <action>", "Action: IGNORE or RESOLVE").addHelpText(
3099
2900
  "after",
3100
- dedent14`
2901
+ dedent13`
3101
2902
 
3102
2903
  Actions:
3103
- RETRY Re-execute the failed operation with the original payload
3104
2904
  IGNORE Mark as intentionally skipped (won't appear in PENDING)
3105
2905
  RESOLVE Mark as manually resolved (e.g., fixed via external system)
3106
2906
 
3107
2907
  Example:
3108
- $ lexq logs action --id <logId> --action RETRY
2908
+ $ lexq logs action --id <logId> --action RESOLVE
3109
2909
  `
3110
2910
  ).action(async (opts) => {
3111
2911
  try {
@@ -3127,9 +2927,9 @@ ${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
3127
2927
  process.exit(1);
3128
2928
  }
3129
2929
  });
3130
- logs.command("bulk-action").description("Bulk process failure logs").requiredOption("--ids <logIds>", "Comma-separated log IDs").requiredOption("--action <action>", "Action: RETRY, IGNORE, or RESOLVE").addHelpText(
2930
+ logs.command("bulk-action").description("Bulk process failure logs").requiredOption("--ids <logIds>", "Comma-separated log IDs").requiredOption("--action <action>", "Action: IGNORE or RESOLVE").addHelpText(
3131
2931
  "after",
3132
- dedent14`
2932
+ dedent13`
3133
2933
 
3134
2934
  Processes each log individually. Failures are skipped with a warning.
3135
2935
 
@@ -3157,11 +2957,11 @@ ${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
3157
2957
 
3158
2958
  // src/commands/webhook-subscriptions.ts
3159
2959
  import "commander";
3160
- import dedent15 from "dedent";
2960
+ import dedent14 from "dedent";
3161
2961
  function registerWebhookSubscriptionCommands(program) {
3162
2962
  const webhooks = program.command("webhook-subscriptions").description("Manage platform event webhook subscriptions").addHelpText(
3163
2963
  "after",
3164
- dedent15`
2964
+ dedent14`
3165
2965
 
3166
2966
  Receive notifications when deployment lifecycle events occur
3167
2967
  (publish, deploy, rollback, undeploy).
@@ -3235,7 +3035,7 @@ ${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
3235
3035
  });
3236
3036
  webhooks.command("save").description("Create or update a webhook subscription").requiredOption("--json <body>", "Request body as JSON string").addHelpText(
3237
3037
  "after",
3238
- dedent15`
3038
+ dedent14`
3239
3039
 
3240
3040
  Examples:
3241
3041
  # Create (Slack format)
@@ -3290,7 +3090,7 @@ ${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
3290
3090
  });
3291
3091
  webhooks.command("delete").description("Delete a webhook subscription").requiredOption("--id <subscriptionId>", "Subscription ID").option("--force", "Skip confirmation prompt").addHelpText(
3292
3092
  "after",
3293
- dedent15`
3093
+ dedent14`
3294
3094
 
3295
3095
  Use --force to skip the confirmation prompt.
3296
3096
 
@@ -3324,7 +3124,7 @@ ${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
3324
3124
  });
3325
3125
  webhooks.command("test").description("Send a test event to verify webhook connectivity").requiredOption("--id <subscriptionId>", "Subscription ID").addHelpText(
3326
3126
  "after",
3327
- dedent15`
3127
+ dedent14`
3328
3128
 
3329
3129
  Sends a test event to the webhook URL and reports the HTTP status code.
3330
3130
  Does not record failures in the failure log.
@@ -3360,7 +3160,7 @@ ${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
3360
3160
 
3361
3161
  // src/commands/serve.ts
3362
3162
  import "commander";
3363
- import dedent18 from "dedent";
3163
+ import dedent17 from "dedent";
3364
3164
 
3365
3165
  // src/mcp/server.ts
3366
3166
  import { readFileSync as readFileSync3 } from "fs";
@@ -3494,8 +3294,8 @@ function registerGroupTools(server, callApi) {
3494
3294
  inputSchema: {
3495
3295
  name: z.string().describe("Group name (unique among non-ARCHIVED)"),
3496
3296
  description: z.string().optional().describe("Group description"),
3497
- activationMode: z.enum(["NONE", "EXCLUSIVE", "MAX_N"]).optional().describe("Conflict resolution mode"),
3498
- activationStrategy: z.enum(["FIRST_MATCH", "HIGHEST_PRIORITY", "MAX_BENEFIT"]).optional().describe("Strategy when mode is EXCLUSIVE or MAX_N"),
3297
+ activationMode: z.enum(ConflictResolutionMode).optional().describe("Conflict resolution mode"),
3298
+ activationStrategy: z.enum(ConflictResolutionStrategy).optional().describe("Strategy when mode is EXCLUSIVE or MAX_N"),
3499
3299
  executionLimit: z.number().int().min(1).optional().describe("Max rule executions (required when mode is MAX_N)"),
3500
3300
  activationGroup: z.string().optional().describe("Activation group name")
3501
3301
  }
@@ -3523,8 +3323,8 @@ function registerGroupTools(server, callApi) {
3523
3323
  description: z.string().optional().describe("New description"),
3524
3324
  status: z.enum(["ACTIVE", "DISABLED"]).optional().describe("Status (DISABLED = emergency stop)"),
3525
3325
  activationGroup: z.string().optional().describe("Activation group (Execution Group) cluster key"),
3526
- activationMode: z.enum(["NONE", "EXCLUSIVE", "MAX_N"]).optional().describe("Conflict resolution mode"),
3527
- activationStrategy: z.enum(["FIRST_MATCH", "HIGHEST_PRIORITY", "MAX_BENEFIT"]).optional().describe("Strategy"),
3326
+ activationMode: z.enum(ConflictResolutionMode).optional().describe("Conflict resolution mode"),
3327
+ activationStrategy: z.enum(ConflictResolutionStrategy).optional().describe("Strategy"),
3528
3328
  executionLimit: z.number().int().min(1).optional().describe("Max rule executions")
3529
3329
  }
3530
3330
  },
@@ -3687,7 +3487,7 @@ function registerVersionTools(server, callApi) {
3687
3487
 
3688
3488
  // src/mcp/tools/rules.ts
3689
3489
  import { z as z3 } from "zod";
3690
- import dedent16 from "dedent";
3490
+ import dedent15 from "dedent";
3691
3491
  function registerRuleTools(server, callApi) {
3692
3492
  server.registerTool(
3693
3493
  "lexq_rules_list",
@@ -3718,7 +3518,7 @@ function registerRuleTools(server, callApi) {
3718
3518
  "lexq_rules_create",
3719
3519
  {
3720
3520
  title: "Create Rule",
3721
- description: dedent16`
3521
+ description: dedent15`
3722
3522
  Create a rule in a DRAFT version. Requires name, condition tree, and actions array. priority is auto-assigned (appended last); use lexq_rules_reorder to change order.
3723
3523
 
3724
3524
  Before creating rules with new fact keys, call lexq_facts_list to check existing facts.
@@ -3751,20 +3551,33 @@ function registerRuleTools(server, callApi) {
3751
3551
  Actions: [{ type, parameters }]
3752
3552
 
3753
3553
  Action parameter schemas:
3754
- - MUTATE_FACT: { refVar: string, operator: "ASSIGN"|"ADD"|"SUB"|"MUL"|"DIV", method: "PERCENTAGE"|"AMOUNT", rate?: number (when PERCENTAGE), value?: number (when AMOUNT), rounding?: RoundingOption } Constraints: DIV + PERCENTAGE is invalid (use MUL with rate/100 inverse). DIV + AMOUNT requires value !== 0.
3755
- - INCREMENT_FACT: { targetVar: string, method: "PERCENTAGE"|"AMOUNT", refVar?: string (required when PERCENTAGE), rate?: number (when PERCENTAGE), value?: number (when AMOUNT), rounding?: RoundingOption } targetVar (accumulation target) must exist at execution; refVar (PERCENTAGE source) must exist when method is PERCENTAGE. Each is supplied as an input fact or written by a prior action in this rule — a missing required fact throws (no 0 default). Note: external system call (e.g. point system sync) is NOT a primitive responsibility. Compose [INCREMENT_FACT, EMIT_EVENT] chain instead.
3756
- - EMIT_EVENT: { integrationId: uuid, eventPayload: object (Map<string,unknown>, ≥1 entry) } eventPayload is passed through to the integration provider as-is. Domain-specific keys (couponId, ticketId, etc.) are routed by the provider, not validated by the engine.
3757
- - BLOCK: { reason: string }
3758
- - EMIT_NOTIFICATION: { integrationId: uuid, targetVar: string, notificationPayload: object (Map<string,unknown>, ≥1 entry) } targetVar identifies the recipient fact (e.g. phone_number / email / device_token) and is REQUIRED — the named fact must be present in the request or the action throws. (Contrast with ADD_TAG, where targetVar is an optional write target that is created if absent.)
3759
- - EMIT_WEBHOOK: { url: string, method: "POST", payloadTemplate?: object } payloadTemplate is optional. Without it, all facts are sent as-is. With it, the object is sent as the HTTP body with {{variables}} replaced at execution time. Variables: {{fact.xxx}}, {{output.xxx}}, {{timestamp}}, {{ruleName}}, {{groupName}}, {{versionNo}}, {{xxx}} (shorthand).
3760
- Platform examples:
3761
- Slack: { "text": "Rule {{ruleName}} fired{{fact.customer_tier}}" }
3762
- Discord: { "content": "Rule {{ruleName}} fired {{fact.customer_tier}}" }
3763
- Generic: { "event": "rule_matched", "rule": "{{ruleName}}", "amount": "{{output.payment_amount}}" }
3764
- - SET_FACT: { key: string, value: string|number|boolean }
3765
- - ADD_TAG: { tag: string, targetVar?: string (defaults to "user_tags") } Appends tag to a LIST_STRING fact, creating it if absent. Adding an existing tag is a no-op (idempotent). Read tags back with HAS_ANY / HAS_ALL / HAS_NONE.
3766
-
3767
- RoundingOption (optional, MUTATE_FACT / INCREMENT_FACT only): { scale: integer (0..16), mode?: "HALF_UP"|"HALF_DOWN"|"HALF_EVEN"|"FLOOR"|"CEILING"|"DOWN"|"UP" } mode defaults to HALF_UP. When omitted, calculator output is preserved at full precision (lossless).
3554
+ - MUTATE_FACT: { targetVar: string, operator: "ASSIGN"|"ADD"|"SUB"|"MUL"|"DIV", method: "PERCENTAGE"|"AMOUNT", operand: number, refVar?: string, rounding?: RoundingOption }
3555
+ targetVar is the fact this action reads and writes. It must exist in facts at execution
3556
+ time as a number supplied as an input fact or written by a prior action in this rule.
3557
+ A missing required fact throws (no 0 default).
3558
+ operand is the arithmetic operand; the unit is dictated by method (percent when
3559
+ PERCENTAGE, absolute amount when AMOUNT). Ranges are not constrained negative values
3560
+ and >100 percentages are valid (refunds, surcharges).
3561
+ refVar is the base for percentage calculation and is OPTIONAL omit it to use targetVar
3562
+ itself. It is only meaningful in PERCENTAGE × {ASSIGN, ADD, SUB}; specifying it in any
3563
+ other cell is an error. Use it when the base differs from the target, e.g.
3564
+ "points += order_total × 5%" → { targetVar: "points", refVar: "order_total",
3565
+ operator: "ADD", method: "PERCENTAGE", operand: 5 }.
3566
+ operator × method matrix:
3567
+ ASSIGN targetVar = operand | targetVar = refVar × operand/100
3568
+ ADD targetVar += operand | targetVar += refVar × operand/100
3569
+ SUB targetVar -= operand | targetVar -= refVar × operand/100
3570
+ MUL targetVar *= operand | targetVar *= (operand/100 + 1)
3571
+ DIV targetVar /= operand | invalid
3572
+ Constraints: DIV + PERCENTAGE is invalid (use MUL with the inverse). DIV + AMOUNT
3573
+ requires operand !== 0.
3574
+ - SET_FACT: { targetVar: string, value: string|number|boolean } Creates the fact if absent
3575
+ — this is the only action that does. MUTATE_FACT requires the target to already exist.
3576
+ - BLOCK: { reason: string } Records a rejection decision. It does NOT halt rule execution —
3577
+ subsequent actions and subsequent winning rules still run. Enforcement is the caller's
3578
+ responsibility; the decision surfaces as the is_blocked fact.
3579
+
3580
+ RoundingOption (optional, MUTATE_FACT only): { scale: integer (0..16), mode?: "HALF_UP"|"HALF_DOWN"|"HALF_EVEN"|"FLOOR"|"CEILING"|"DOWN"|"UP" } mode defaults to HALF_UP. When omitted, calculator output is preserved at full precision (lossless).
3768
3581
  `,
3769
3582
  inputSchema: {
3770
3583
  groupId: z3.string().uuid().describe("Policy group ID"),
@@ -3927,7 +3740,7 @@ function registerFactTools(server, callApi) {
3927
3740
  "lexq_facts_action_metadata",
3928
3741
  {
3929
3742
  title: "Get Action Runtime Fact Metadata",
3930
- description: "Retrieve runtime fact requirements per Action type. For each Action, shows which input facts must be present in the execution payload (e.g. MUTATE_FACT requires its refVar fact; INCREMENT_FACT always requires targetVar, plus refVar when method is PERCENTAGE). A required fact absent at runtime throws \u2014 the engine never defaults to 0. Facts are supplied as input or written by a prior action in the same rule; Actions never create a fact from nothing. Static data, safe to cache in-session.",
3743
+ description: "Retrieve runtime fact requirements per Action type. For each Action, shows which input facts must be present in the execution payload \u2014 e.g. MUTATE_FACT always requires its targetVar fact, plus refVar when one is specified. The factRequired flag describes the FACT, not the parameter: refVar is an optional parameter, but if you specify it the named fact must exist. A required fact absent at runtime throws \u2014 the engine never defaults to 0. Facts are supplied as input or written by a prior action in the same rule; only SET_FACT creates a fact from nothing. Static data, safe to cache in-session.",
3931
3744
  inputSchema: {}
3932
3745
  },
3933
3746
  async () => callApi("GET", "schema/action-metadata")
@@ -4115,13 +3928,13 @@ function registerDeployTools(server, callApi) {
4115
3928
 
4116
3929
  // src/mcp/tools/analytics.ts
4117
3930
  import { z as z6 } from "zod";
4118
- import dedent17 from "dedent";
3931
+ import dedent16 from "dedent";
4119
3932
  function registerAnalyticsTools(server, callApi) {
4120
3933
  server.registerTool(
4121
3934
  "lexq_dry_run",
4122
3935
  {
4123
3936
  title: "Dry Run",
4124
- description: dedent17`
3937
+ description: dedent16`
4125
3938
  Execute a single dry run against a version. Tests how rules evaluate given input facts without side effects.
4126
3939
 
4127
3940
  Returns:
@@ -4136,14 +3949,13 @@ function registerAnalyticsTools(server, callApi) {
4136
3949
  inputSchema: {
4137
3950
  versionId: z6.string().uuid().describe("Policy version ID to test against"),
4138
3951
  facts: z6.string().describe('JSON string of facts object, e.g. {"payment_amount":100000}'),
4139
- includeDebugInfo: z6.boolean().default(true).describe("Include execution and decision traces"),
4140
- mockExternalCalls: z6.boolean().default(true).describe("Mock external integration calls")
3952
+ includeDebugInfo: z6.boolean().default(true).describe("Include execution and decision traces")
4141
3953
  }
4142
3954
  },
4143
- async ({ versionId, facts, includeDebugInfo, mockExternalCalls }) => {
3955
+ async ({ versionId, facts, includeDebugInfo }) => {
4144
3956
  const parsedFacts = JSON.parse(facts);
4145
3957
  return callApi("POST", `analytics/dry-run/versions/${versionId}`, {
4146
- body: { facts: parsedFacts, includeDebugInfo, mockExternalCalls }
3958
+ body: { facts: parsedFacts, includeDebugInfo }
4147
3959
  });
4148
3960
  }
4149
3961
  );
@@ -4151,7 +3963,7 @@ function registerAnalyticsTools(server, callApi) {
4151
3963
  "lexq_dry_run_compare",
4152
3964
  {
4153
3965
  title: "Dry Run Compare",
4154
- description: dedent17`
3966
+ description: dedent16`
4155
3967
  Compare dry run results between two versions using the same input facts. Useful for validating changes.
4156
3968
 
4157
3969
  Returns:
@@ -4187,7 +3999,7 @@ function registerAnalyticsTools(server, callApi) {
4187
3999
  "lexq_simulation_start",
4188
4000
  {
4189
4001
  title: "Start Simulation",
4190
- description: dedent17`
4002
+ description: dedent16`
4191
4003
  Start an Impact Simulation against historical, uploaded, or inline data.
4192
4004
 
4193
4005
  dataset.type and dataset.source are BOTH required, and must be paired:
@@ -4285,7 +4097,7 @@ function registerAnalyticsTools(server, callApi) {
4285
4097
  "lexq_dataset_upload",
4286
4098
  {
4287
4099
  title: "Upload Dataset",
4288
- description: dedent17`
4100
+ description: dedent16`
4289
4101
  Upload inline CSV or JSON content as a simulation dataset.
4290
4102
  The content is uploaded to S3 and a path is returned in the "path" field.
4291
4103
 
@@ -4396,7 +4208,7 @@ function registerReplayTools(server, callApi) {
4396
4208
  "lexq_replay_decision",
4397
4209
  {
4398
4210
  title: "Replay a Decision",
4399
- description: "Re-evaluate a past execution (traceId) against a candidate version and return the decision diff (decisionChanged, effect changes, fired rules) plus a determinism verdict. Synchronous and free of charge (TPS throttle only). External effects (webhooks, notifications) are always mocked \u2014 nothing fires.",
4211
+ description: "Re-evaluate a past execution (traceId) against a candidate version and return the decision diff (decisionChanged, effect changes, fired rules) plus a determinism verdict. Synchronous and free of charge (TPS throttle only). A replay sends no webhook, notification, or event: rule actions produce no outward effects.",
4400
4212
  inputSchema: {
4401
4213
  traceId: z8.string().describe("Trace ID of the past execution to replay"),
4402
4214
  candidateVersionId: z8.string().uuid().describe("Version to re-evaluate against")
@@ -4557,102 +4369,26 @@ function registerProvenanceTools(server, callApi) {
4557
4369
  );
4558
4370
  }
4559
4371
 
4560
- // src/mcp/tools/integrations.ts
4561
- import { z as z11 } from "zod";
4562
- function registerIntegrationTools(server, callApi) {
4563
- server.registerTool(
4564
- "lexq_integrations_list",
4565
- {
4566
- title: "List Integrations",
4567
- description: "List all external integrations (webhooks, CRM, notification, etc.).",
4568
- inputSchema: {
4569
- page: z11.number().int().min(0).default(0).describe("Page number"),
4570
- size: z11.number().int().min(1).max(100).default(20).describe("Page size"),
4571
- type: z11.enum(["COUPON", "POINT", "NOTIFICATION", "CRM", "MESSENGER", "WEBHOOK"]).optional().describe("Filter by integration type")
4572
- }
4573
- },
4574
- async ({ page, size, type }) => {
4575
- const params = paginationParams(page, size);
4576
- if (type) params.type = type;
4577
- return callApi("GET", "integrations", { params });
4578
- }
4579
- );
4580
- server.registerTool(
4581
- "lexq_integrations_get",
4582
- {
4583
- title: "Get Integration",
4584
- description: "Get integration detail by ID.",
4585
- inputSchema: {
4586
- integrationId: z11.string().uuid().describe("Integration ID")
4587
- }
4588
- },
4589
- async ({ integrationId }) => callApi("GET", `integrations/${integrationId}`)
4590
- );
4591
- server.registerTool(
4592
- "lexq_integrations_save",
4593
- {
4594
- title: "Save Integration",
4595
- 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.",
4596
- inputSchema: {
4597
- id: z11.string().uuid().optional().describe("Integration ID (omit to create, provide to update)"),
4598
- type: z11.enum(["COUPON", "POINT", "NOTIFICATION", "CRM", "MESSENGER", "WEBHOOK"]).describe("Integration type"),
4599
- name: z11.string().describe("Integration name"),
4600
- baseUrl: z11.string().describe("Base URL of the external service"),
4601
- credential: z11.string().optional().describe("API key or token for the service"),
4602
- additionalConfig: z11.string().optional().describe("JSON string of additional config key-value pairs"),
4603
- isActive: z11.boolean().default(true).describe("Whether the integration is active")
4604
- }
4605
- },
4606
- async ({ additionalConfig, ...rest }) => {
4607
- const body = { ...rest };
4608
- if (additionalConfig) body.additionalConfig = JSON.parse(additionalConfig);
4609
- return callApi("POST", "integrations", { body });
4610
- }
4611
- );
4612
- server.registerTool(
4613
- "lexq_integrations_delete",
4614
- {
4615
- title: "Delete Integration",
4616
- description: "Delete an integration by ID.",
4617
- inputSchema: {
4618
- integrationId: z11.string().uuid().describe("Integration ID")
4619
- }
4620
- },
4621
- async ({ integrationId }) => callApi("DELETE", `integrations/${integrationId}`)
4622
- );
4623
- server.registerTool(
4624
- "lexq_integrations_config_spec",
4625
- {
4626
- title: "Integration Config Spec",
4627
- description: "Show available integration types and their required configuration fields.",
4628
- inputSchema: {}
4629
- },
4630
- async () => callApi("GET", "integrations/config-spec")
4631
- );
4632
- }
4633
-
4634
4372
  // src/mcp/tools/logs.ts
4635
- import { z as z12 } from "zod";
4373
+ import { z as z11 } from "zod";
4636
4374
  function registerLogTools(server, callApi) {
4637
4375
  server.registerTool(
4638
4376
  "lexq_logs_list",
4639
4377
  {
4640
4378
  title: "List Failure Logs",
4641
- description: "List system failure logs from background tasks (webhook calls, coupon issuance, etc.).",
4379
+ description: "List system failure logs from background tasks (platform event webhooks, scheduled deployments).",
4642
4380
  inputSchema: {
4643
- page: z12.number().int().min(0).default(0).describe("Page number"),
4644
- size: z12.number().int().min(1).max(100).default(20).describe("Page size"),
4645
- category: z12.enum(TaskCategory).optional().describe("Task category"),
4646
- taskType: z12.enum(TaskType).optional().describe("Task type"),
4647
- status: z12.enum(FailureStatus).optional().describe("Log status"),
4648
- keyword: z12.string().optional().describe("Search in refId, refSubId, errorMessage"),
4649
- startDate: z12.string().optional().describe("Start date (yyyy-MM-dd)"),
4650
- endDate: z12.string().optional().describe("End date (yyyy-MM-dd)")
4381
+ page: z11.number().int().min(0).default(0).describe("Page number"),
4382
+ size: z11.number().int().min(1).max(100).default(20).describe("Page size"),
4383
+ taskType: z11.enum(TaskType).optional().describe("Task type"),
4384
+ status: z11.enum(FailureStatus).optional().describe("Log status"),
4385
+ keyword: z11.string().optional().describe("Search in refId, refSubId, errorMessage"),
4386
+ startDate: z11.string().optional().describe("Start date (yyyy-MM-dd)"),
4387
+ endDate: z11.string().optional().describe("End date (yyyy-MM-dd)")
4651
4388
  }
4652
4389
  },
4653
- async ({ page, size, category, taskType, status, keyword, startDate, endDate }) => {
4390
+ async ({ page, size, taskType, status, keyword, startDate, endDate }) => {
4654
4391
  const params = paginationParams(page, size);
4655
- if (category) params.category = category;
4656
4392
  if (taskType) params.taskType = taskType;
4657
4393
  if (status) params.status = status;
4658
4394
  if (keyword) params.keyword = keyword;
@@ -4667,7 +4403,7 @@ function registerLogTools(server, callApi) {
4667
4403
  title: "Get Failure Log",
4668
4404
  description: "Get failure log detail by ID.",
4669
4405
  inputSchema: {
4670
- logId: z12.string().uuid().describe("Failure log ID")
4406
+ logId: z11.string().uuid().describe("Failure log ID")
4671
4407
  }
4672
4408
  },
4673
4409
  async ({ logId }) => callApi("GET", `failure-logs/${logId}`)
@@ -4676,10 +4412,10 @@ function registerLogTools(server, callApi) {
4676
4412
  "lexq_logs_action",
4677
4413
  {
4678
4414
  title: "Process Failure Log",
4679
- description: "Process a single failure log: RETRY (re-execute with original payload), RESOLVE (mark as manually fixed), or IGNORE (skip intentionally).",
4415
+ description: "Process a single failure log: RESOLVE (mark as manually fixed) or IGNORE (skip intentionally).",
4680
4416
  inputSchema: {
4681
- logId: z12.string().uuid().describe("Failure log ID"),
4682
- action: z12.enum(FailureAction).describe("Action to take")
4417
+ logId: z11.string().uuid().describe("Failure log ID"),
4418
+ action: z11.enum(FailureAction).describe("Action to take")
4683
4419
  }
4684
4420
  },
4685
4421
  async ({ logId, action }) => callApi("POST", `failure-logs/${logId}/actions`, {
@@ -4692,8 +4428,8 @@ function registerLogTools(server, callApi) {
4692
4428
  title: "Bulk Process Failure Logs",
4693
4429
  description: "Process multiple failure logs at once. Provide an array of log IDs and the action.",
4694
4430
  inputSchema: {
4695
- logIds: z12.array(z12.string().uuid()).describe("Array of failure log IDs"),
4696
- action: z12.enum(FailureAction).describe("Action to apply to all logs")
4431
+ logIds: z11.array(z11.string().uuid()).describe("Array of failure log IDs"),
4432
+ action: z11.enum(FailureAction).describe("Action to apply to all logs")
4697
4433
  }
4698
4434
  },
4699
4435
  async ({ logIds, action }) => callApi("POST", "failure-logs/bulk-actions", {
@@ -4703,7 +4439,7 @@ function registerLogTools(server, callApi) {
4703
4439
  }
4704
4440
 
4705
4441
  // src/mcp/tools/webhook-subscriptions.ts
4706
- import { z as z13 } from "zod";
4442
+ import { z as z12 } from "zod";
4707
4443
  function registerWebhookSubscriptionTools(server, callApi) {
4708
4444
  server.registerTool(
4709
4445
  "lexq_webhook_subscriptions_list",
@@ -4711,8 +4447,8 @@ function registerWebhookSubscriptionTools(server, callApi) {
4711
4447
  title: "List Webhook Subscriptions",
4712
4448
  description: "List platform event webhook subscriptions. These receive deployment lifecycle notifications (publish, deploy, rollback, undeploy).",
4713
4449
  inputSchema: {
4714
- page: z13.number().int().min(0).default(0).describe("Page number"),
4715
- size: z13.number().int().min(1).max(100).default(20).describe("Page size")
4450
+ page: z12.number().int().min(0).default(0).describe("Page number"),
4451
+ size: z12.number().int().min(1).max(100).default(20).describe("Page size")
4716
4452
  }
4717
4453
  },
4718
4454
  async ({ page, size }) => {
@@ -4726,7 +4462,7 @@ function registerWebhookSubscriptionTools(server, callApi) {
4726
4462
  title: "Get Webhook Subscription",
4727
4463
  description: "Get webhook subscription detail by ID.",
4728
4464
  inputSchema: {
4729
- id: z13.string().uuid().describe("Webhook subscription ID")
4465
+ id: z12.string().uuid().describe("Webhook subscription ID")
4730
4466
  }
4731
4467
  },
4732
4468
  async ({ id }) => callApi("GET", `webhook-subscriptions/${id}`)
@@ -4737,13 +4473,13 @@ function registerWebhookSubscriptionTools(server, callApi) {
4737
4473
  title: "Save Webhook Subscription",
4738
4474
  description: 'Create or update a webhook subscription. Omit id to create, provide id to update. Events: VERSION_PUBLISHED, DEPLOYED, ROLLED_BACK, UNDEPLOYED. Formats: GENERIC (full JSON), SLACK ({"text": "..."}).',
4739
4475
  inputSchema: {
4740
- id: z13.string().uuid().optional().describe("Subscription ID (omit to create, provide to update)"),
4741
- name: z13.string().min(1).describe("Subscription name (unique per tenant)"),
4742
- webhookUrl: z13.string().url().describe("Webhook endpoint URL"),
4743
- subscribedEvents: z13.array(z13.enum(PlatformEventType)).min(1).describe("Events to subscribe to"),
4744
- payloadFormat: z13.enum(WebhookPayloadFormat).optional().default("GENERIC").describe("Payload format"),
4745
- secret: z13.string().optional().describe("HMAC-SHA256 signing secret"),
4746
- isActive: z13.boolean().optional().default(true).describe("Whether the subscription is active")
4476
+ id: z12.string().uuid().optional().describe("Subscription ID (omit to create, provide to update)"),
4477
+ name: z12.string().min(1).describe("Subscription name (unique per tenant)"),
4478
+ webhookUrl: z12.string().url().describe("Webhook endpoint URL"),
4479
+ subscribedEvents: z12.array(z12.enum(PlatformEventType)).min(1).describe("Events to subscribe to"),
4480
+ payloadFormat: z12.enum(WebhookPayloadFormat).optional().default("GENERIC").describe("Payload format"),
4481
+ secret: z12.string().optional().describe("HMAC-SHA256 signing secret"),
4482
+ isActive: z12.boolean().optional().default(true).describe("Whether the subscription is active")
4747
4483
  }
4748
4484
  },
4749
4485
  async ({ ...body }) => callApi("POST", "webhook-subscriptions", { body })
@@ -4754,7 +4490,7 @@ function registerWebhookSubscriptionTools(server, callApi) {
4754
4490
  title: "Delete Webhook Subscription",
4755
4491
  description: "Delete a webhook subscription by ID.",
4756
4492
  inputSchema: {
4757
- id: z13.string().uuid().describe("Webhook subscription ID")
4493
+ id: z12.string().uuid().describe("Webhook subscription ID")
4758
4494
  }
4759
4495
  },
4760
4496
  async ({ id }) => callApi("DELETE", `webhook-subscriptions/${id}`)
@@ -4765,7 +4501,7 @@ function registerWebhookSubscriptionTools(server, callApi) {
4765
4501
  title: "Test Webhook Subscription",
4766
4502
  description: "Send a test event to verify webhook connectivity. Returns the HTTP status code and success/failure message.",
4767
4503
  inputSchema: {
4768
- id: z13.string().uuid().describe("Webhook subscription ID")
4504
+ id: z12.string().uuid().describe("Webhook subscription ID")
4769
4505
  }
4770
4506
  },
4771
4507
  async ({ id }) => callApi("POST", `webhook-subscriptions/${id}/test`)
@@ -4773,7 +4509,7 @@ function registerWebhookSubscriptionTools(server, callApi) {
4773
4509
  }
4774
4510
 
4775
4511
  // src/mcp/tools/domain-templates.ts
4776
- import { z as z14 } from "zod";
4512
+ import { z as z13 } from "zod";
4777
4513
  function registerDomainTemplateTools(server, callApi) {
4778
4514
  server.registerTool(
4779
4515
  "lexq_domain_templates_list",
@@ -4790,7 +4526,7 @@ function registerDomainTemplateTools(server, callApi) {
4790
4526
  title: "Preview Domain Template",
4791
4527
  description: "Preview exactly what a domain template will provision before applying it: the fact definitions it registers, the sample rules it creates, and an apply plan. This is a read-only dry run \u2014 nothing is created. Only ACTIVE templates can be previewed.",
4792
4528
  inputSchema: {
4793
- template: z14.string().describe(
4529
+ template: z13.string().describe(
4794
4530
  "Domain template key (e.g. ECOMMERCE). Use lexq_domain_templates_list to see available keys \u2014 currently only ECOMMERCE is ACTIVE."
4795
4531
  )
4796
4532
  }
@@ -4803,8 +4539,8 @@ function registerDomainTemplateTools(server, callApi) {
4803
4539
  title: "Apply Domain Template",
4804
4540
  description: "Apply a domain template to the current tenant. Creates the template's fact definitions and a new policy group pre-populated with its sample rules as a DRAFT version. Existing facts are skipped \u2014 apply is additive and never overwrites existing schema. Run lexq_domain_templates_preview first to review what will be created. Only ACTIVE templates can be applied.",
4805
4541
  inputSchema: {
4806
- template: z14.string().describe("Domain template key to apply (e.g. ECOMMERCE)."),
4807
- customName: z14.string().optional().describe(
4542
+ template: z13.string().describe("Domain template key to apply (e.g. ECOMMERCE)."),
4543
+ customName: z13.string().optional().describe(
4808
4544
  "Optional custom name for the policy group that gets created. If omitted, the template's default name is used."
4809
4545
  )
4810
4546
  }
@@ -4830,7 +4566,6 @@ function registerAllTools(server, callApi) {
4830
4566
  registerReplayTools(server, callApi);
4831
4567
  registerHistoryTools(server, callApi);
4832
4568
  registerProvenanceTools(server, callApi);
4833
- registerIntegrationTools(server, callApi);
4834
4569
  registerLogTools(server, callApi);
4835
4570
  registerDomainTemplateTools(server, callApi);
4836
4571
  registerWebhookSubscriptionTools(server, callApi);
@@ -4861,7 +4596,7 @@ async function startMcpServer() {
4861
4596
  function registerServeCommand(program) {
4862
4597
  program.command("serve").description("Start LexQ as a server for AI agent integrations").option("--mcp", "Start as MCP (Model Context Protocol) server over stdio").addHelpText(
4863
4598
  "after",
4864
- dedent18`
4599
+ dedent17`
4865
4600
 
4866
4601
  Example:
4867
4602
  $ lexq serve --mcp
@@ -4892,11 +4627,11 @@ function registerServeCommand(program) {
4892
4627
 
4893
4628
  // src/commands/domain-templates.ts
4894
4629
  import "commander";
4895
- import dedent19 from "dedent";
4630
+ import dedent18 from "dedent";
4896
4631
  function registerDomainTemplateCommands(program) {
4897
4632
  const templates = program.command("domain-templates").description("Browse and apply domain templates").addHelpText(
4898
4633
  "after",
4899
- dedent19`
4634
+ dedent18`
4900
4635
 
4901
4636
  A domain template is an industry-specific starter pack of fact
4902
4637
  definitions and sample rules. Applying one provisions a ready-to-use
@@ -4944,7 +4679,7 @@ function registerDomainTemplateCommands(program) {
4944
4679
  });
4945
4680
  templates.command("preview").description("Preview what a domain template provisions").requiredOption("--template <key>", "Domain template key (e.g. ECOMMERCE)").addHelpText(
4946
4681
  "after",
4947
- dedent19`
4682
+ dedent18`
4948
4683
 
4949
4684
  Read-only dry run — shows the fact definitions and sample rules the
4950
4685
  template will create. Nothing is provisioned.
@@ -4973,7 +4708,7 @@ function registerDomainTemplateCommands(program) {
4973
4708
  });
4974
4709
  templates.command("apply").description("Apply a domain template to the current tenant").requiredOption("--template <key>", "Domain template key (e.g. ECOMMERCE)").option("--name <n>", "Custom name for the policy group that gets created").option("--force", "Skip confirmation prompt").addHelpText(
4975
4710
  "after",
4976
- dedent19`
4711
+ dedent18`
4977
4712
 
4978
4713
  Creates the template's fact definitions and a new DRAFT policy group
4979
4714
  populated with its sample rules. Existing facts are skipped — apply is
@@ -5052,7 +4787,6 @@ function createCli() {
5052
4787
  registerHistoryCommands(program);
5053
4788
  registerReplayCommands(program);
5054
4789
  registerProvenanceCommands(program);
5055
- registerIntegrationCommands(program);
5056
4790
  registerLogCommands(program);
5057
4791
  registerWebhookSubscriptionCommands(program);
5058
4792
  registerServeCommand(program);