@lexq/cli 0.1.36 → 0.1.37

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
@@ -2183,13 +2183,140 @@ function resolveBody(opts) {
2183
2183
  return {};
2184
2184
  }
2185
2185
 
2186
- // src/commands/history.ts
2186
+ // src/commands/profile.ts
2187
2187
  import "commander";
2188
2188
  import dedent9 from "dedent";
2189
+
2190
+ // src/types/enums.ts
2191
+ var ProfileCacheState = ["HIT", "MISS"];
2192
+ var FailureStatus = ["PENDING", "RESOLVED", "IGNORED"];
2193
+ var FailureAction = ["RETRY", "IGNORE", "RESOLVE"];
2194
+ var TaskCategory = ["INTEGRATION", "INTERNAL"];
2195
+ var TaskType = [
2196
+ // Integration
2197
+ "COUPON_ISSUE",
2198
+ "COUPON_CANCEL",
2199
+ "POINT_EARN",
2200
+ "POINT_USE",
2201
+ "POINT_REFUND",
2202
+ "NOTIFICATION_SEND",
2203
+ "CRM_SYNC_USER",
2204
+ "CRM_ADD_TAG",
2205
+ "WEBHOOK_EXECUTE",
2206
+ // Internal
2207
+ "IMAGE_PROCESSING",
2208
+ "DAILY_SETTLEMENT",
2209
+ "PLATFORM_WEBHOOK"
2210
+ ];
2211
+ var PlatformEventType = [
2212
+ "VERSION_PUBLISHED",
2213
+ "DEPLOYED",
2214
+ "ROLLED_BACK",
2215
+ "UNDEPLOYED"
2216
+ ];
2217
+ var WebhookPayloadFormat = ["GENERIC", "SLACK"];
2218
+
2219
+ // src/commands/profile.ts
2220
+ var ms = (nanos) => nanos == null ? "\u2013" : (nanos / 1e6).toFixed(2);
2221
+ var msWithUnit = (nanos) => nanos == null ? "\u2013" : `${(nanos / 1e6).toFixed(2)}ms`;
2222
+ function registerProfileCommands(program) {
2223
+ program.command("profile <groupId>").description("Per-rule latency profile with relative slow-rule flags").option("--rule <ruleId>", "Single-rule detail (distributions + 60s window series)").option("--version <versionId>", "Version to inspect (default: live version)").option("--from <instant>", "Window start, ISO-8601 instant (default: 24h ago)").option("--to <instant>", "Window end, ISO-8601 instant (default: now)").option("--cache <state>", "Cache dimension for the rule table: HIT | MISS (default: HIT)").addHelpText(
2224
+ "after",
2225
+ dedent9`
2226
+
2227
+ Slow-rule judgment is relative only: flagged = p50 ≥ 10× the median of
2228
+ per-rule p50s within the group. Absolute ms thresholds are intentionally
2229
+ not supported. Percentiles are withheld (–) when n < 100; TOTAL is
2230
+ recorded for every call, rule detail from a deterministic 1% sample.
2231
+
2232
+ Examples:
2233
+ $ lexq profile <groupId>
2234
+ $ lexq profile <groupId> --cache MISS --from 2026-07-01T00:00:00Z
2235
+ $ lexq profile <groupId> --rule <ruleId> --version <versionId>
2236
+ `
2237
+ ).action(async (groupId, opts) => {
2238
+ try {
2239
+ const globalOpts = program.opts();
2240
+ const format = globalOpts.format ?? "json";
2241
+ if (opts.cache && !ProfileCacheState.includes(opts.cache)) {
2242
+ throw new Error(`--cache must be one of: ${ProfileCacheState.join(" | ")}`);
2243
+ }
2244
+ const params = {};
2245
+ if (opts.version) params.versionId = opts.version;
2246
+ if (opts.from) params.from = opts.from;
2247
+ if (opts.to) params.to = opts.to;
2248
+ if (opts.cache) params.cacheState = opts.cache;
2249
+ const clientOpts = {
2250
+ apiKey: globalOpts.apiKey,
2251
+ baseUrl: globalOpts.baseUrl,
2252
+ dryRun: globalOpts.dryRun,
2253
+ verbose: globalOpts.verbose
2254
+ };
2255
+ if (opts.rule) {
2256
+ const data2 = await apiRequest(
2257
+ "GET",
2258
+ `policy-groups/${groupId}/profile/rules/${opts.rule}`,
2259
+ { ...clientOpts, params }
2260
+ );
2261
+ if (format === "table") {
2262
+ console.error("note: --rule detail is nested; printing JSON (table not supported)");
2263
+ }
2264
+ printJson(data2);
2265
+ return;
2266
+ }
2267
+ const data = await apiRequest("GET", `policy-groups/${groupId}/profile`, {
2268
+ ...clientOpts,
2269
+ params
2270
+ });
2271
+ if (format !== "table") {
2272
+ printJson(data);
2273
+ return;
2274
+ }
2275
+ console.log(`window : ${data.from} ~ ${data.to} (cache: ${data.ruleCacheState})`);
2276
+ console.log(`version : ${data.policyVersionId ?? "\u2013 (no live version)"}`);
2277
+ for (const s of data.summary) {
2278
+ const t = s.total;
2279
+ console.log(
2280
+ `TOTAL ${s.cacheState.padEnd(4)}: n=${t.n} p50=${msWithUnit(t.p50Nanos)} p95=${msWithUnit(t.p95Nanos)} p99=${msWithUnit(t.p99Nanos)}`
2281
+ );
2282
+ }
2283
+ for (const b of data.baselines) {
2284
+ const base = b.status === "OK" ? `${msWithUnit(b.baselineP50Nanos)} (cohort ${b.cohortSize})` : `\u2013 (${b.status}, cohort ${b.cohortSize})`;
2285
+ console.log(`baseline ${b.phase.padEnd(9)}: ${base}`);
2286
+ }
2287
+ if (data.droppedRows > 0) {
2288
+ console.log(`\u26A0 droppedRows=${data.droppedRows} (corrupt histogram rows skipped)`);
2289
+ }
2290
+ printTable(
2291
+ ["Rule", "Phase", "n", "p50(ms)", "p95(ms)", "p99(ms)", "\xD7base", "Flagged"],
2292
+ data.rules.flatMap(
2293
+ (rule) => rule.phases.map((p) => [
2294
+ rule.ruleId.substring(0, 12),
2295
+ p.phase,
2296
+ String(p.stats.n),
2297
+ ms(p.stats.p50Nanos),
2298
+ ms(p.stats.p95Nanos),
2299
+ ms(p.stats.p99Nanos),
2300
+ p.baselineMultiple == null ? "\u2013" : `${p.baselineMultiple.toFixed(1)}\xD7`,
2301
+ p.flagged ? "YES" : ""
2302
+ ])
2303
+ ),
2304
+ { truncate: 24 }
2305
+ );
2306
+ } catch (error) {
2307
+ printError(error);
2308
+ process.exit(1);
2309
+ }
2310
+ });
2311
+ }
2312
+
2313
+ // src/commands/history.ts
2314
+ import "commander";
2315
+ import dedent10 from "dedent";
2189
2316
  function registerHistoryCommands(program) {
2190
2317
  const history = program.command("history").description("Execution history").addHelpText(
2191
2318
  "after",
2192
- dedent9`
2319
+ dedent10`
2193
2320
 
2194
2321
  View and analyze policy execution logs from production traffic.
2195
2322
 
@@ -2203,7 +2330,7 @@ function registerHistoryCommands(program) {
2203
2330
  );
2204
2331
  history.command("list").description("List execution history").option("--trace-id <traceId>", "Filter by trace ID").option("--group-id <groupId>", "Filter by policy group").option("--version-id <versionId>", "Filter by version").option("--status <status>", "Filter by status (SUCCESS, NO_MATCH, ERROR, TIMEOUT)").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(
2205
2332
  "after",
2206
- dedent9`
2333
+ dedent10`
2207
2334
 
2208
2335
  Examples:
2209
2336
  $ lexq history list --status ERROR --format table
@@ -2257,7 +2384,7 @@ ${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
2257
2384
  });
2258
2385
  history.command("get").description("Get execution detail").requiredOption("--id <traceId>", "Trace ID").addHelpText(
2259
2386
  "after",
2260
- dedent9`
2387
+ dedent10`
2261
2388
 
2262
2389
  Returns the full execution detail including request facts, result traces,
2263
2390
  and decision traces (SELECTED, NO_MATCH, BLOCKED, etc.).
@@ -2283,7 +2410,7 @@ ${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
2283
2410
  });
2284
2411
  history.command("stats").description("Get execution statistics").option("--group-id <groupId>", "Filter by policy group").option("--start-date <date>", "Start date (yyyy-MM-dd)").option("--end-date <date>", "End date (yyyy-MM-dd)").addHelpText(
2285
2412
  "after",
2286
- dedent9`
2413
+ dedent10`
2287
2414
 
2288
2415
  Shows total executions, success/no-match/failure counts, success rate, and avg latency.
2289
2416
 
@@ -2332,11 +2459,11 @@ ${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
2332
2459
 
2333
2460
  // src/commands/replay.ts
2334
2461
  import "commander";
2335
- import dedent10 from "dedent";
2462
+ import dedent11 from "dedent";
2336
2463
  function registerReplayCommands(program) {
2337
2464
  const replay = program.command("replay").description("Decision Replay").addHelpText(
2338
2465
  "after",
2339
- dedent10`
2466
+ dedent11`
2340
2467
 
2341
2468
  Re-evaluate past production executions against a candidate version.
2342
2469
 
@@ -2352,7 +2479,7 @@ function registerReplayCommands(program) {
2352
2479
  );
2353
2480
  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(
2354
2481
  "after",
2355
- dedent10`
2482
+ dedent11`
2356
2483
 
2357
2484
  Free of charge (TPS throttle only). Returns decisionChanged, effect
2358
2485
  changes, fired rules on both sides, and a determinism verdict.
@@ -2378,7 +2505,7 @@ function registerReplayCommands(program) {
2378
2505
  });
2379
2506
  replay.command("start").description("Submit a window replay job (blast radius)").requiredOption("--version-id <versionId>", "Candidate version to re-evaluate against").requiredOption("--from <date>", "Window start date (yyyy-MM-dd)").requiredOption("--to <date>", "Window end date (yyyy-MM-dd)").option("--max-records <number>", "Sample cap (hard cap 50k)").addHelpText(
2380
2507
  "after",
2381
- dedent10`
2508
+ dedent11`
2382
2509
 
2383
2510
  Billed per replayed record (REPLAY metric). Poll with "lexq replay get".
2384
2511
 
@@ -2476,11 +2603,11 @@ ${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
2476
2603
 
2477
2604
  // src/commands/provenance.ts
2478
2605
  import "commander";
2479
- import dedent11 from "dedent";
2606
+ import dedent12 from "dedent";
2480
2607
  function registerProvenanceCommands(program) {
2481
2608
  const provenance = program.command("provenance").description("Decision Provenance").addHelpText(
2482
2609
  "after",
2483
- dedent11`
2610
+ dedent12`
2484
2611
 
2485
2612
  Trace who authored, published, and deployed the rules behind a decision.
2486
2613
 
@@ -2506,7 +2633,7 @@ function registerProvenanceCommands(program) {
2506
2633
  });
2507
2634
  provenance.command("reveal-audits").description("List PII reveal audits (who revealed what, when)").option("--trace-id <traceId>", "Filter by trace ID (exact)").option("--fact-key <factKey>", "Filter by fact key (partial, case-insensitive)").option("--revealed-by <operatorId>", "Filter by operator ID (exact)").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(
2508
2635
  "after",
2509
- dedent11`
2636
+ dedent12`
2510
2637
 
2511
2638
  Metadata only — revealed values are never stored or returned.
2512
2639
 
@@ -2559,11 +2686,11 @@ ${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
2559
2686
 
2560
2687
  // src/commands/integrations.ts
2561
2688
  import "commander";
2562
- import dedent12 from "dedent";
2689
+ import dedent13 from "dedent";
2563
2690
  function registerIntegrationCommands(program) {
2564
2691
  const integrations = program.command("integrations").description("Manage external integrations").addHelpText(
2565
2692
  "after",
2566
- dedent12`
2693
+ dedent13`
2567
2694
 
2568
2695
  Integrations connect rule actions to external services (webhooks, coupons,
2569
2696
  points, notifications, CRM, messengers).
@@ -2633,7 +2760,7 @@ ${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
2633
2760
  });
2634
2761
  integrations.command("save").description("Create or update an integration").requiredOption("--json <body>", "Request body as JSON string").addHelpText(
2635
2762
  "after",
2636
- dedent12`
2763
+ dedent13`
2637
2764
 
2638
2765
  Examples:
2639
2766
  # Create
@@ -2683,7 +2810,7 @@ ${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
2683
2810
  });
2684
2811
  integrations.command("delete").description("Delete an integration").requiredOption("--id <integrationId>", "Integration ID").option("--force", "Skip confirmation prompt").addHelpText(
2685
2812
  "after",
2686
- dedent12`
2813
+ dedent13`
2687
2814
 
2688
2815
  Rules referencing this integration will fail at execution time.
2689
2816
  Use --force to skip confirmation.
@@ -2715,7 +2842,7 @@ ${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
2715
2842
  });
2716
2843
  integrations.command("config-spec").description("Get integration configuration field specs").addHelpText(
2717
2844
  "after",
2718
- dedent12`
2845
+ dedent13`
2719
2846
 
2720
2847
  Shows required and optional configuration fields for each integration type.
2721
2848
 
@@ -2741,41 +2868,11 @@ ${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
2741
2868
 
2742
2869
  // src/commands/logs.ts
2743
2870
  import "commander";
2744
- import dedent13 from "dedent";
2745
-
2746
- // src/types/enums.ts
2747
- var FailureStatus = ["PENDING", "RESOLVED", "IGNORED"];
2748
- var FailureAction = ["RETRY", "IGNORE", "RESOLVE"];
2749
- var TaskCategory = ["INTEGRATION", "INTERNAL"];
2750
- var TaskType = [
2751
- // Integration
2752
- "COUPON_ISSUE",
2753
- "COUPON_CANCEL",
2754
- "POINT_EARN",
2755
- "POINT_USE",
2756
- "POINT_REFUND",
2757
- "NOTIFICATION_SEND",
2758
- "CRM_SYNC_USER",
2759
- "CRM_ADD_TAG",
2760
- "WEBHOOK_EXECUTE",
2761
- // Internal
2762
- "IMAGE_PROCESSING",
2763
- "DAILY_SETTLEMENT",
2764
- "PLATFORM_WEBHOOK"
2765
- ];
2766
- var PlatformEventType = [
2767
- "VERSION_PUBLISHED",
2768
- "DEPLOYED",
2769
- "ROLLED_BACK",
2770
- "UNDEPLOYED"
2771
- ];
2772
- var WebhookPayloadFormat = ["GENERIC", "SLACK"];
2773
-
2774
- // src/commands/logs.ts
2871
+ import dedent14 from "dedent";
2775
2872
  function registerLogCommands(program) {
2776
2873
  const logs = program.command("logs").description("Failure logs").addHelpText(
2777
2874
  "after",
2778
- dedent13`
2875
+ dedent14`
2779
2876
 
2780
2877
  System failure logs (DLQ) for background tasks — webhook calls, coupon issuance,
2781
2878
  point operations, notifications, and platform event webhooks.
@@ -2792,7 +2889,7 @@ function registerLogCommands(program) {
2792
2889
  );
2793
2890
  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(
2794
2891
  "after",
2795
- dedent13`
2892
+ dedent14`
2796
2893
 
2797
2894
  Examples:
2798
2895
  $ lexq logs list --status PENDING --format table
@@ -2843,7 +2940,7 @@ ${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
2843
2940
  });
2844
2941
  logs.command("get").description("Get failure log detail").requiredOption("--id <logId>", "Log ID").addHelpText(
2845
2942
  "after",
2846
- dedent13`
2943
+ dedent14`
2847
2944
 
2848
2945
  Includes the full payload that was used for the failed operation.
2849
2946
  Use this to inspect what went wrong before deciding to RETRY or RESOLVE.
@@ -2865,7 +2962,7 @@ ${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
2865
2962
  });
2866
2963
  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(
2867
2964
  "after",
2868
- dedent13`
2965
+ dedent14`
2869
2966
 
2870
2967
  Actions:
2871
2968
  RETRY Re-execute the failed operation with the original payload
@@ -2897,7 +2994,7 @@ ${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
2897
2994
  });
2898
2995
  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(
2899
2996
  "after",
2900
- dedent13`
2997
+ dedent14`
2901
2998
 
2902
2999
  Processes each log individually. Failures are skipped with a warning.
2903
3000
 
@@ -2925,11 +3022,11 @@ ${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
2925
3022
 
2926
3023
  // src/commands/webhook-subscriptions.ts
2927
3024
  import "commander";
2928
- import dedent14 from "dedent";
3025
+ import dedent15 from "dedent";
2929
3026
  function registerWebhookSubscriptionCommands(program) {
2930
3027
  const webhooks = program.command("webhook-subscriptions").description("Manage platform event webhook subscriptions").addHelpText(
2931
3028
  "after",
2932
- dedent14`
3029
+ dedent15`
2933
3030
 
2934
3031
  Receive notifications when deployment lifecycle events occur
2935
3032
  (publish, deploy, rollback, undeploy).
@@ -3003,7 +3100,7 @@ ${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
3003
3100
  });
3004
3101
  webhooks.command("save").description("Create or update a webhook subscription").requiredOption("--json <body>", "Request body as JSON string").addHelpText(
3005
3102
  "after",
3006
- dedent14`
3103
+ dedent15`
3007
3104
 
3008
3105
  Examples:
3009
3106
  # Create (Slack format)
@@ -3058,7 +3155,7 @@ ${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
3058
3155
  });
3059
3156
  webhooks.command("delete").description("Delete a webhook subscription").requiredOption("--id <subscriptionId>", "Subscription ID").option("--force", "Skip confirmation prompt").addHelpText(
3060
3157
  "after",
3061
- dedent14`
3158
+ dedent15`
3062
3159
 
3063
3160
  Use --force to skip the confirmation prompt.
3064
3161
 
@@ -3092,7 +3189,7 @@ ${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
3092
3189
  });
3093
3190
  webhooks.command("test").description("Send a test event to verify webhook connectivity").requiredOption("--id <subscriptionId>", "Subscription ID").addHelpText(
3094
3191
  "after",
3095
- dedent14`
3192
+ dedent15`
3096
3193
 
3097
3194
  Sends a test event to the webhook URL and reports the HTTP status code.
3098
3195
  Does not record failures in the failure log.
@@ -3128,7 +3225,7 @@ ${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
3128
3225
 
3129
3226
  // src/commands/serve.ts
3130
3227
  import "commander";
3131
- import dedent17 from "dedent";
3228
+ import dedent18 from "dedent";
3132
3229
 
3133
3230
  // src/mcp/server.ts
3134
3231
  import { readFileSync as readFileSync3 } from "fs";
@@ -3455,7 +3552,7 @@ function registerVersionTools(server, callApi) {
3455
3552
 
3456
3553
  // src/mcp/tools/rules.ts
3457
3554
  import { z as z3 } from "zod";
3458
- import dedent15 from "dedent";
3555
+ import dedent16 from "dedent";
3459
3556
  function registerRuleTools(server, callApi) {
3460
3557
  server.registerTool(
3461
3558
  "lexq_rules_list",
@@ -3486,7 +3583,7 @@ function registerRuleTools(server, callApi) {
3486
3583
  "lexq_rules_create",
3487
3584
  {
3488
3585
  title: "Create Rule",
3489
- description: dedent15`
3586
+ description: dedent16`
3490
3587
  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.
3491
3588
 
3492
3589
  Before creating rules with new fact keys, call lexq_facts_list to check existing facts.
@@ -3832,13 +3929,13 @@ function registerDeployTools(server, callApi) {
3832
3929
 
3833
3930
  // src/mcp/tools/analytics.ts
3834
3931
  import { z as z6 } from "zod";
3835
- import dedent16 from "dedent";
3932
+ import dedent17 from "dedent";
3836
3933
  function registerAnalyticsTools(server, callApi) {
3837
3934
  server.registerTool(
3838
3935
  "lexq_dry_run",
3839
3936
  {
3840
3937
  title: "Dry Run",
3841
- description: dedent16`
3938
+ description: dedent17`
3842
3939
  Execute a single dry run against a version. Tests how rules evaluate given input facts without side effects.
3843
3940
 
3844
3941
  Returns:
@@ -3868,7 +3965,7 @@ function registerAnalyticsTools(server, callApi) {
3868
3965
  "lexq_dry_run_compare",
3869
3966
  {
3870
3967
  title: "Dry Run Compare",
3871
- description: dedent16`
3968
+ description: dedent17`
3872
3969
  Compare dry run results between two versions using the same input facts. Useful for validating changes.
3873
3970
 
3874
3971
  Returns:
@@ -3904,7 +4001,7 @@ function registerAnalyticsTools(server, callApi) {
3904
4001
  "lexq_simulation_start",
3905
4002
  {
3906
4003
  title: "Start Simulation",
3907
- description: dedent16`
4004
+ description: dedent17`
3908
4005
  Start an Impact Simulation against historical, uploaded, or inline data.
3909
4006
 
3910
4007
  dataset.type and dataset.source are BOTH required, and must be paired:
@@ -4002,7 +4099,7 @@ function registerAnalyticsTools(server, callApi) {
4002
4099
  "lexq_dataset_upload",
4003
4100
  {
4004
4101
  title: "Upload Dataset",
4005
- description: dedent16`
4102
+ description: dedent17`
4006
4103
  Upload inline CSV or JSON content as a simulation dataset.
4007
4104
  The content is uploaded to S3 and a path is returned in the "path" field.
4008
4105
 
@@ -4058,8 +4155,56 @@ function registerAnalyticsTools(server, callApi) {
4058
4155
  );
4059
4156
  }
4060
4157
 
4061
- // src/mcp/tools/replay.ts
4158
+ // src/mcp/tools/profile.ts
4062
4159
  import { z as z7 } from "zod";
4160
+ var RELATIVE_THRESHOLD = "flagged = p50 \u2265 10\xD7 median of per-rule p50s within the group; absolute thresholds are intentionally not supported.";
4161
+ function profileParams(opts) {
4162
+ const params = {};
4163
+ if (opts.versionId) params.versionId = opts.versionId;
4164
+ if (opts.from) params.from = opts.from;
4165
+ if (opts.to) params.to = opts.to;
4166
+ if (opts.cacheState) params.cacheState = opts.cacheState;
4167
+ return params;
4168
+ }
4169
+ function registerProfileTools(server, callApi) {
4170
+ server.registerTool(
4171
+ "lexq_profile_overview",
4172
+ {
4173
+ title: "Group Latency Profile",
4174
+ description: "Per-rule latency profile of a policy group over a time window: group TOTAL distribution split by cache state (HIT = compiled ruleset cache hit, MISS = deep-load + compile), a per-rule CONDITION/ACTION percentile table, and slow-rule flags. " + RELATIVE_THRESHOLD + " Every percentile is accompanied by its sample count n; percentiles are withheld (null) when n < 100, and baselines report INSUFFICIENT_COHORT when fewer than 3 rules qualify. Rule detail comes from a deterministic 1% sample of calls; TOTAL is recorded for every call. Defaults: last 24h, live version, cacheState HIT.",
4175
+ inputSchema: {
4176
+ groupId: z7.string().uuid().describe("Policy group ID"),
4177
+ versionId: z7.string().uuid().optional().describe("Version to inspect (default: live version)"),
4178
+ from: z7.string().optional().describe("Window start, ISO-8601 instant (e.g. 2026-07-01T00:00:00Z). Default: 24h ago"),
4179
+ to: z7.string().optional().describe("Window end, ISO-8601 instant. Default: now"),
4180
+ cacheState: z7.enum(["HIT", "MISS"]).optional().describe("Cache dimension for the rule table and judgment (default: HIT)")
4181
+ }
4182
+ },
4183
+ async ({ groupId, versionId, from, to, cacheState }) => callApi("GET", `policy-groups/${groupId}/profile`, {
4184
+ params: profileParams({ versionId, from, to, cacheState })
4185
+ })
4186
+ );
4187
+ server.registerTool(
4188
+ "lexq_profile_rule",
4189
+ {
4190
+ title: "Rule Latency Detail",
4191
+ description: "Single-rule latency detail: merged phase \xD7 cacheState distributions plus a per-window time series (60s windows). Missing windows are genuine gaps \u2014 never interpolated. Series points carry each window's own values; percentiles in merged distributions are withheld (null) when n < 100. " + RELATIVE_THRESHOLD,
4192
+ inputSchema: {
4193
+ groupId: z7.string().uuid().describe("Policy group ID"),
4194
+ ruleId: z7.string().uuid().describe("Rule ID (from lexq_profile_overview)"),
4195
+ versionId: z7.string().uuid().optional().describe("Version to inspect (default: live version)"),
4196
+ from: z7.string().optional().describe("Window start, ISO-8601 instant. Default: 24h ago"),
4197
+ to: z7.string().optional().describe("Window end, ISO-8601 instant. Default: now")
4198
+ }
4199
+ },
4200
+ async ({ groupId, ruleId, versionId, from, to }) => callApi("GET", `policy-groups/${groupId}/profile/rules/${ruleId}`, {
4201
+ params: profileParams({ versionId, from, to })
4202
+ })
4203
+ );
4204
+ }
4205
+
4206
+ // src/mcp/tools/replay.ts
4207
+ import { z as z8 } from "zod";
4063
4208
  function registerReplayTools(server, callApi) {
4064
4209
  server.registerTool(
4065
4210
  "lexq_replay_decision",
@@ -4067,8 +4212,8 @@ function registerReplayTools(server, callApi) {
4067
4212
  title: "Replay a Decision",
4068
4213
  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.",
4069
4214
  inputSchema: {
4070
- traceId: z7.string().describe("Trace ID of the past execution to replay"),
4071
- candidateVersionId: z7.string().uuid().describe("Version to re-evaluate against")
4215
+ traceId: z8.string().describe("Trace ID of the past execution to replay"),
4216
+ candidateVersionId: z8.string().uuid().describe("Version to re-evaluate against")
4072
4217
  }
4073
4218
  },
4074
4219
  async ({ traceId, candidateVersionId }) => callApi("POST", "replay/decisions", { body: { traceId, candidateVersionId } })
@@ -4079,10 +4224,10 @@ function registerReplayTools(server, callApi) {
4079
4224
  title: "Start Window Replay (Blast Radius)",
4080
4225
  description: "Submit an async job that replays a date window of past executions against a candidate version and measures the blast radius (how many decisions change). Billed per replayed record (REPLAY metric); VIEWER role cannot submit. Poll with lexq_replay_status.",
4081
4226
  inputSchema: {
4082
- candidateVersionId: z7.string().uuid().describe("Version to re-evaluate against"),
4083
- from: z7.string().describe("Window start date (yyyy-MM-dd)"),
4084
- to: z7.string().describe("Window end date (yyyy-MM-dd)"),
4085
- maxRecords: z7.number().int().min(1).optional().describe("Sample cap (server default applies; hard cap 50k)")
4227
+ candidateVersionId: z8.string().uuid().describe("Version to re-evaluate against"),
4228
+ from: z8.string().describe("Window start date (yyyy-MM-dd)"),
4229
+ to: z8.string().describe("Window end date (yyyy-MM-dd)"),
4230
+ maxRecords: z8.number().int().min(1).optional().describe("Sample cap (server default applies; hard cap 50k)")
4086
4231
  }
4087
4232
  },
4088
4233
  async ({ candidateVersionId, from, to, maxRecords }) => callApi("POST", "replay/jobs", { body: { candidateVersionId, from, to, maxRecords } })
@@ -4093,7 +4238,7 @@ function registerReplayTools(server, callApi) {
4093
4238
  title: "Get Replay Job Status",
4094
4239
  description: "Poll a window replay job. RUNNING shows progress 0\u2013100; COMPLETED fills summary and changedSamples; FAILED carries errorMessage. capped=true means the window exceeded the sample cap and only part was replayed.",
4095
4240
  inputSchema: {
4096
- jobId: z7.string().describe("Replay job ID from lexq_replay_start")
4241
+ jobId: z8.string().describe("Replay job ID from lexq_replay_start")
4097
4242
  }
4098
4243
  },
4099
4244
  async ({ jobId }) => callApi("GET", `replay/jobs/${jobId}`)
@@ -4104,8 +4249,8 @@ function registerReplayTools(server, callApi) {
4104
4249
  title: "List Replay Jobs",
4105
4250
  description: "List window replay job history (reverse-chronological). Lightweight items \u2014 use lexq_replay_status for summary and changed samples.",
4106
4251
  inputSchema: {
4107
- page: z7.number().int().min(0).default(0).describe("Page number"),
4108
- size: z7.number().int().min(1).max(100).default(20).describe("Page size")
4252
+ page: z8.number().int().min(0).default(0).describe("Page number"),
4253
+ size: z8.number().int().min(1).max(100).default(20).describe("Page size")
4109
4254
  }
4110
4255
  },
4111
4256
  async ({ page, size }) => callApi("GET", "replay/jobs", { params: paginationParams(page, size) })
@@ -4116,7 +4261,7 @@ function registerReplayTools(server, callApi) {
4116
4261
  title: "Cancel Replay Job",
4117
4262
  description: "Cooperatively cancel a PENDING or RUNNING window replay job. Other states are rejected. VIEWER role cannot cancel.",
4118
4263
  inputSchema: {
4119
- jobId: z7.string().describe("Replay job ID")
4264
+ jobId: z8.string().describe("Replay job ID")
4120
4265
  }
4121
4266
  },
4122
4267
  async ({ jobId }) => callApi("POST", `replay/jobs/${jobId}/cancel`)
@@ -4124,7 +4269,7 @@ function registerReplayTools(server, callApi) {
4124
4269
  }
4125
4270
 
4126
4271
  // src/mcp/tools/history.ts
4127
- import { z as z8 } from "zod";
4272
+ import { z as z9 } from "zod";
4128
4273
  function registerHistoryTools(server, callApi) {
4129
4274
  server.registerTool(
4130
4275
  "lexq_history_list",
@@ -4132,14 +4277,14 @@ function registerHistoryTools(server, callApi) {
4132
4277
  title: "List Execution History",
4133
4278
  description: "List policy execution history. Shows trace ID, group, version, status, match result, and latency.",
4134
4279
  inputSchema: {
4135
- page: z8.number().int().min(0).default(0).describe("Page number"),
4136
- size: z8.number().int().min(1).max(100).default(20).describe("Page size"),
4137
- traceId: z8.string().optional().describe("Filter by trace ID"),
4138
- groupId: z8.string().uuid().optional().describe("Filter by policy group"),
4139
- versionId: z8.string().uuid().optional().describe("Filter by version"),
4140
- status: z8.enum(["SUCCESS", "NO_MATCH", "ERROR", "TIMEOUT"]).optional().describe("Filter by execution status"),
4141
- startDate: z8.string().optional().describe("Start date (yyyy-MM-dd)"),
4142
- endDate: z8.string().optional().describe("End date (yyyy-MM-dd)")
4280
+ page: z9.number().int().min(0).default(0).describe("Page number"),
4281
+ size: z9.number().int().min(1).max(100).default(20).describe("Page size"),
4282
+ traceId: z9.string().optional().describe("Filter by trace ID"),
4283
+ groupId: z9.string().uuid().optional().describe("Filter by policy group"),
4284
+ versionId: z9.string().uuid().optional().describe("Filter by version"),
4285
+ status: z9.enum(["SUCCESS", "NO_MATCH", "ERROR", "TIMEOUT"]).optional().describe("Filter by execution status"),
4286
+ startDate: z9.string().optional().describe("Start date (yyyy-MM-dd)"),
4287
+ endDate: z9.string().optional().describe("End date (yyyy-MM-dd)")
4143
4288
  }
4144
4289
  },
4145
4290
  async ({ page, size, traceId, groupId, versionId, status, startDate, endDate }) => {
@@ -4159,7 +4304,7 @@ function registerHistoryTools(server, callApi) {
4159
4304
  title: "Get Execution Detail",
4160
4305
  description: "Get full execution detail including inputFacts, mutatedFacts, generatedVariables, executionTraces, and decisionTraces.",
4161
4306
  inputSchema: {
4162
- traceId: z8.string().describe("Trace ID from execution history")
4307
+ traceId: z9.string().describe("Trace ID from execution history")
4163
4308
  }
4164
4309
  },
4165
4310
  async ({ traceId }) => callApi("GET", `execution/history/${traceId}`)
@@ -4170,9 +4315,9 @@ function registerHistoryTools(server, callApi) {
4170
4315
  title: "Execution Statistics",
4171
4316
  description: "Get execution KPIs: total executions, success/failure counts, success rate, and average latency.",
4172
4317
  inputSchema: {
4173
- groupId: z8.string().uuid().optional().describe("Filter by policy group"),
4174
- startDate: z8.string().optional().describe("Start date (yyyy-MM-dd)"),
4175
- endDate: z8.string().optional().describe("End date (yyyy-MM-dd)")
4318
+ groupId: z9.string().uuid().optional().describe("Filter by policy group"),
4319
+ startDate: z9.string().optional().describe("Start date (yyyy-MM-dd)"),
4320
+ endDate: z9.string().optional().describe("End date (yyyy-MM-dd)")
4176
4321
  }
4177
4322
  },
4178
4323
  async ({ groupId, startDate, endDate }) => {
@@ -4186,7 +4331,7 @@ function registerHistoryTools(server, callApi) {
4186
4331
  }
4187
4332
 
4188
4333
  // src/mcp/tools/provenance.ts
4189
- import { z as z9 } from "zod";
4334
+ import { z as z10 } from "zod";
4190
4335
  function registerProvenanceTools(server, callApi) {
4191
4336
  server.registerTool(
4192
4337
  "lexq_provenance_get",
@@ -4194,7 +4339,7 @@ function registerProvenanceTools(server, callApi) {
4194
4339
  title: "Get Decision Provenance",
4195
4340
  description: "Get the lineage of a single decision: what was decided, deterministic why per rule, input facts (PII facts are masked as \u2022\u2022\u2022\u2022\u2022\u2022 with maskedKeys listing them \u2014 values are revealable only in the console, audited), the authored/published/deployed responsibility chain, and the rule snapshot fingerprint.",
4196
4341
  inputSchema: {
4197
- traceId: z9.string().describe("Trace ID of the execution")
4342
+ traceId: z10.string().describe("Trace ID of the execution")
4198
4343
  }
4199
4344
  },
4200
4345
  async ({ traceId }) => callApi("GET", `provenance/${traceId}`)
@@ -4205,13 +4350,13 @@ function registerProvenanceTools(server, callApi) {
4205
4350
  title: "List PII Reveal Audits",
4206
4351
  description: "List the PII reveal audit ledger \u2014 who revealed which fact of which trace, and when. Metadata only; revealed values are never stored or returned. Use for monthly access-log inspection and SIEM collection.",
4207
4352
  inputSchema: {
4208
- page: z9.number().int().min(0).default(0).describe("Page number"),
4209
- size: z9.number().int().min(1).max(100).default(20).describe("Page size"),
4210
- traceId: z9.string().optional().describe("Filter by trace ID (exact match)"),
4211
- revealedBy: z9.string().optional().describe("Filter by operator ID (exact match)"),
4212
- factKey: z9.string().optional().describe("Filter by fact key (partial match, case-insensitive)"),
4213
- startDate: z9.string().optional().describe("Start date (yyyy-MM-dd)"),
4214
- endDate: z9.string().optional().describe("End date (yyyy-MM-dd)")
4353
+ page: z10.number().int().min(0).default(0).describe("Page number"),
4354
+ size: z10.number().int().min(1).max(100).default(20).describe("Page size"),
4355
+ traceId: z10.string().optional().describe("Filter by trace ID (exact match)"),
4356
+ revealedBy: z10.string().optional().describe("Filter by operator ID (exact match)"),
4357
+ factKey: z10.string().optional().describe("Filter by fact key (partial match, case-insensitive)"),
4358
+ startDate: z10.string().optional().describe("Start date (yyyy-MM-dd)"),
4359
+ endDate: z10.string().optional().describe("End date (yyyy-MM-dd)")
4215
4360
  }
4216
4361
  },
4217
4362
  async ({ page, size, traceId, revealedBy, factKey, startDate, endDate }) => {
@@ -4227,7 +4372,7 @@ function registerProvenanceTools(server, callApi) {
4227
4372
  }
4228
4373
 
4229
4374
  // src/mcp/tools/integrations.ts
4230
- import { z as z10 } from "zod";
4375
+ import { z as z11 } from "zod";
4231
4376
  function registerIntegrationTools(server, callApi) {
4232
4377
  server.registerTool(
4233
4378
  "lexq_integrations_list",
@@ -4235,9 +4380,9 @@ function registerIntegrationTools(server, callApi) {
4235
4380
  title: "List Integrations",
4236
4381
  description: "List all external integrations (webhooks, CRM, notification, etc.).",
4237
4382
  inputSchema: {
4238
- page: z10.number().int().min(0).default(0).describe("Page number"),
4239
- size: z10.number().int().min(1).max(100).default(20).describe("Page size"),
4240
- type: z10.enum(["COUPON", "POINT", "NOTIFICATION", "CRM", "MESSENGER", "WEBHOOK"]).optional().describe("Filter by integration type")
4383
+ page: z11.number().int().min(0).default(0).describe("Page number"),
4384
+ size: z11.number().int().min(1).max(100).default(20).describe("Page size"),
4385
+ type: z11.enum(["COUPON", "POINT", "NOTIFICATION", "CRM", "MESSENGER", "WEBHOOK"]).optional().describe("Filter by integration type")
4241
4386
  }
4242
4387
  },
4243
4388
  async ({ page, size, type }) => {
@@ -4252,7 +4397,7 @@ function registerIntegrationTools(server, callApi) {
4252
4397
  title: "Get Integration",
4253
4398
  description: "Get integration detail by ID.",
4254
4399
  inputSchema: {
4255
- integrationId: z10.string().uuid().describe("Integration ID")
4400
+ integrationId: z11.string().uuid().describe("Integration ID")
4256
4401
  }
4257
4402
  },
4258
4403
  async ({ integrationId }) => callApi("GET", `integrations/${integrationId}`)
@@ -4263,13 +4408,13 @@ function registerIntegrationTools(server, callApi) {
4263
4408
  title: "Save Integration",
4264
4409
  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.",
4265
4410
  inputSchema: {
4266
- id: z10.string().uuid().optional().describe("Integration ID (omit to create, provide to update)"),
4267
- type: z10.enum(["COUPON", "POINT", "NOTIFICATION", "CRM", "MESSENGER", "WEBHOOK"]).describe("Integration type"),
4268
- name: z10.string().describe("Integration name"),
4269
- baseUrl: z10.string().describe("Base URL of the external service"),
4270
- credential: z10.string().optional().describe("API key or token for the service"),
4271
- additionalConfig: z10.string().optional().describe("JSON string of additional config key-value pairs"),
4272
- isActive: z10.boolean().default(true).describe("Whether the integration is active")
4411
+ id: z11.string().uuid().optional().describe("Integration ID (omit to create, provide to update)"),
4412
+ type: z11.enum(["COUPON", "POINT", "NOTIFICATION", "CRM", "MESSENGER", "WEBHOOK"]).describe("Integration type"),
4413
+ name: z11.string().describe("Integration name"),
4414
+ baseUrl: z11.string().describe("Base URL of the external service"),
4415
+ credential: z11.string().optional().describe("API key or token for the service"),
4416
+ additionalConfig: z11.string().optional().describe("JSON string of additional config key-value pairs"),
4417
+ isActive: z11.boolean().default(true).describe("Whether the integration is active")
4273
4418
  }
4274
4419
  },
4275
4420
  async ({ additionalConfig, ...rest }) => {
@@ -4284,7 +4429,7 @@ function registerIntegrationTools(server, callApi) {
4284
4429
  title: "Delete Integration",
4285
4430
  description: "Delete an integration by ID.",
4286
4431
  inputSchema: {
4287
- integrationId: z10.string().uuid().describe("Integration ID")
4432
+ integrationId: z11.string().uuid().describe("Integration ID")
4288
4433
  }
4289
4434
  },
4290
4435
  async ({ integrationId }) => callApi("DELETE", `integrations/${integrationId}`)
@@ -4301,7 +4446,7 @@ function registerIntegrationTools(server, callApi) {
4301
4446
  }
4302
4447
 
4303
4448
  // src/mcp/tools/logs.ts
4304
- import { z as z11 } from "zod";
4449
+ import { z as z12 } from "zod";
4305
4450
  function registerLogTools(server, callApi) {
4306
4451
  server.registerTool(
4307
4452
  "lexq_logs_list",
@@ -4309,14 +4454,14 @@ function registerLogTools(server, callApi) {
4309
4454
  title: "List Failure Logs",
4310
4455
  description: "List system failure logs from background tasks (webhook calls, coupon issuance, etc.).",
4311
4456
  inputSchema: {
4312
- page: z11.number().int().min(0).default(0).describe("Page number"),
4313
- size: z11.number().int().min(1).max(100).default(20).describe("Page size"),
4314
- category: z11.enum(TaskCategory).optional().describe("Task category"),
4315
- taskType: z11.enum(TaskType).optional().describe("Task type"),
4316
- status: z11.enum(FailureStatus).optional().describe("Log status"),
4317
- keyword: z11.string().optional().describe("Search in refId, refSubId, errorMessage"),
4318
- startDate: z11.string().optional().describe("Start date (yyyy-MM-dd)"),
4319
- endDate: z11.string().optional().describe("End date (yyyy-MM-dd)")
4457
+ page: z12.number().int().min(0).default(0).describe("Page number"),
4458
+ size: z12.number().int().min(1).max(100).default(20).describe("Page size"),
4459
+ category: z12.enum(TaskCategory).optional().describe("Task category"),
4460
+ taskType: z12.enum(TaskType).optional().describe("Task type"),
4461
+ status: z12.enum(FailureStatus).optional().describe("Log status"),
4462
+ keyword: z12.string().optional().describe("Search in refId, refSubId, errorMessage"),
4463
+ startDate: z12.string().optional().describe("Start date (yyyy-MM-dd)"),
4464
+ endDate: z12.string().optional().describe("End date (yyyy-MM-dd)")
4320
4465
  }
4321
4466
  },
4322
4467
  async ({ page, size, category, taskType, status, keyword, startDate, endDate }) => {
@@ -4336,7 +4481,7 @@ function registerLogTools(server, callApi) {
4336
4481
  title: "Get Failure Log",
4337
4482
  description: "Get failure log detail by ID.",
4338
4483
  inputSchema: {
4339
- logId: z11.string().uuid().describe("Failure log ID")
4484
+ logId: z12.string().uuid().describe("Failure log ID")
4340
4485
  }
4341
4486
  },
4342
4487
  async ({ logId }) => callApi("GET", `failure-logs/${logId}`)
@@ -4347,8 +4492,8 @@ function registerLogTools(server, callApi) {
4347
4492
  title: "Process Failure Log",
4348
4493
  description: "Process a single failure log: RETRY (re-execute with original payload), RESOLVE (mark as manually fixed), or IGNORE (skip intentionally).",
4349
4494
  inputSchema: {
4350
- logId: z11.string().uuid().describe("Failure log ID"),
4351
- action: z11.enum(FailureAction).describe("Action to take")
4495
+ logId: z12.string().uuid().describe("Failure log ID"),
4496
+ action: z12.enum(FailureAction).describe("Action to take")
4352
4497
  }
4353
4498
  },
4354
4499
  async ({ logId, action }) => callApi("POST", `failure-logs/${logId}/actions`, {
@@ -4361,8 +4506,8 @@ function registerLogTools(server, callApi) {
4361
4506
  title: "Bulk Process Failure Logs",
4362
4507
  description: "Process multiple failure logs at once. Provide an array of log IDs and the action.",
4363
4508
  inputSchema: {
4364
- logIds: z11.array(z11.string().uuid()).describe("Array of failure log IDs"),
4365
- action: z11.enum(FailureAction).describe("Action to apply to all logs")
4509
+ logIds: z12.array(z12.string().uuid()).describe("Array of failure log IDs"),
4510
+ action: z12.enum(FailureAction).describe("Action to apply to all logs")
4366
4511
  }
4367
4512
  },
4368
4513
  async ({ logIds, action }) => callApi("POST", "failure-logs/bulk-actions", {
@@ -4372,7 +4517,7 @@ function registerLogTools(server, callApi) {
4372
4517
  }
4373
4518
 
4374
4519
  // src/mcp/tools/webhook-subscriptions.ts
4375
- import { z as z12 } from "zod";
4520
+ import { z as z13 } from "zod";
4376
4521
  function registerWebhookSubscriptionTools(server, callApi) {
4377
4522
  server.registerTool(
4378
4523
  "lexq_webhook_subscriptions_list",
@@ -4380,8 +4525,8 @@ function registerWebhookSubscriptionTools(server, callApi) {
4380
4525
  title: "List Webhook Subscriptions",
4381
4526
  description: "List platform event webhook subscriptions. These receive deployment lifecycle notifications (publish, deploy, rollback, undeploy).",
4382
4527
  inputSchema: {
4383
- page: z12.number().int().min(0).default(0).describe("Page number"),
4384
- size: z12.number().int().min(1).max(100).default(20).describe("Page size")
4528
+ page: z13.number().int().min(0).default(0).describe("Page number"),
4529
+ size: z13.number().int().min(1).max(100).default(20).describe("Page size")
4385
4530
  }
4386
4531
  },
4387
4532
  async ({ page, size }) => {
@@ -4395,7 +4540,7 @@ function registerWebhookSubscriptionTools(server, callApi) {
4395
4540
  title: "Get Webhook Subscription",
4396
4541
  description: "Get webhook subscription detail by ID.",
4397
4542
  inputSchema: {
4398
- id: z12.string().uuid().describe("Webhook subscription ID")
4543
+ id: z13.string().uuid().describe("Webhook subscription ID")
4399
4544
  }
4400
4545
  },
4401
4546
  async ({ id }) => callApi("GET", `webhook-subscriptions/${id}`)
@@ -4406,13 +4551,13 @@ function registerWebhookSubscriptionTools(server, callApi) {
4406
4551
  title: "Save Webhook Subscription",
4407
4552
  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": "..."}).',
4408
4553
  inputSchema: {
4409
- id: z12.string().uuid().optional().describe("Subscription ID (omit to create, provide to update)"),
4410
- name: z12.string().min(1).describe("Subscription name (unique per tenant)"),
4411
- webhookUrl: z12.string().url().describe("Webhook endpoint URL"),
4412
- subscribedEvents: z12.array(z12.enum(PlatformEventType)).min(1).describe("Events to subscribe to"),
4413
- payloadFormat: z12.enum(WebhookPayloadFormat).optional().default("GENERIC").describe("Payload format"),
4414
- secret: z12.string().optional().describe("HMAC-SHA256 signing secret"),
4415
- isActive: z12.boolean().optional().default(true).describe("Whether the subscription is active")
4554
+ id: z13.string().uuid().optional().describe("Subscription ID (omit to create, provide to update)"),
4555
+ name: z13.string().min(1).describe("Subscription name (unique per tenant)"),
4556
+ webhookUrl: z13.string().url().describe("Webhook endpoint URL"),
4557
+ subscribedEvents: z13.array(z13.enum(PlatformEventType)).min(1).describe("Events to subscribe to"),
4558
+ payloadFormat: z13.enum(WebhookPayloadFormat).optional().default("GENERIC").describe("Payload format"),
4559
+ secret: z13.string().optional().describe("HMAC-SHA256 signing secret"),
4560
+ isActive: z13.boolean().optional().default(true).describe("Whether the subscription is active")
4416
4561
  }
4417
4562
  },
4418
4563
  async ({ ...body }) => callApi("POST", "webhook-subscriptions", { body })
@@ -4423,7 +4568,7 @@ function registerWebhookSubscriptionTools(server, callApi) {
4423
4568
  title: "Delete Webhook Subscription",
4424
4569
  description: "Delete a webhook subscription by ID.",
4425
4570
  inputSchema: {
4426
- id: z12.string().uuid().describe("Webhook subscription ID")
4571
+ id: z13.string().uuid().describe("Webhook subscription ID")
4427
4572
  }
4428
4573
  },
4429
4574
  async ({ id }) => callApi("DELETE", `webhook-subscriptions/${id}`)
@@ -4434,7 +4579,7 @@ function registerWebhookSubscriptionTools(server, callApi) {
4434
4579
  title: "Test Webhook Subscription",
4435
4580
  description: "Send a test event to verify webhook connectivity. Returns the HTTP status code and success/failure message.",
4436
4581
  inputSchema: {
4437
- id: z12.string().uuid().describe("Webhook subscription ID")
4582
+ id: z13.string().uuid().describe("Webhook subscription ID")
4438
4583
  }
4439
4584
  },
4440
4585
  async ({ id }) => callApi("POST", `webhook-subscriptions/${id}/test`)
@@ -4442,7 +4587,7 @@ function registerWebhookSubscriptionTools(server, callApi) {
4442
4587
  }
4443
4588
 
4444
4589
  // src/mcp/tools/domain-templates.ts
4445
- import { z as z13 } from "zod";
4590
+ import { z as z14 } from "zod";
4446
4591
  function registerDomainTemplateTools(server, callApi) {
4447
4592
  server.registerTool(
4448
4593
  "lexq_domain_templates_list",
@@ -4459,7 +4604,7 @@ function registerDomainTemplateTools(server, callApi) {
4459
4604
  title: "Preview Domain Template",
4460
4605
  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.",
4461
4606
  inputSchema: {
4462
- template: z13.string().describe(
4607
+ template: z14.string().describe(
4463
4608
  "Domain template key (e.g. ECOMMERCE). Use lexq_domain_templates_list to see available keys \u2014 currently only ECOMMERCE is ACTIVE."
4464
4609
  )
4465
4610
  }
@@ -4472,8 +4617,8 @@ function registerDomainTemplateTools(server, callApi) {
4472
4617
  title: "Apply Domain Template",
4473
4618
  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.",
4474
4619
  inputSchema: {
4475
- template: z13.string().describe("Domain template key to apply (e.g. ECOMMERCE)."),
4476
- customName: z13.string().optional().describe(
4620
+ template: z14.string().describe("Domain template key to apply (e.g. ECOMMERCE)."),
4621
+ customName: z14.string().optional().describe(
4477
4622
  "Optional custom name for the policy group that gets created. If omitted, the template's default name is used."
4478
4623
  )
4479
4624
  }
@@ -4495,6 +4640,7 @@ function registerAllTools(server, callApi) {
4495
4640
  registerFactTools(server, callApi);
4496
4641
  registerDeployTools(server, callApi);
4497
4642
  registerAnalyticsTools(server, callApi);
4643
+ registerProfileTools(server, callApi);
4498
4644
  registerReplayTools(server, callApi);
4499
4645
  registerHistoryTools(server, callApi);
4500
4646
  registerProvenanceTools(server, callApi);
@@ -4529,7 +4675,7 @@ async function startMcpServer() {
4529
4675
  function registerServeCommand(program) {
4530
4676
  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(
4531
4677
  "after",
4532
- dedent17`
4678
+ dedent18`
4533
4679
 
4534
4680
  Example:
4535
4681
  $ lexq serve --mcp
@@ -4560,11 +4706,11 @@ function registerServeCommand(program) {
4560
4706
 
4561
4707
  // src/commands/domain-templates.ts
4562
4708
  import "commander";
4563
- import dedent18 from "dedent";
4709
+ import dedent19 from "dedent";
4564
4710
  function registerDomainTemplateCommands(program) {
4565
4711
  const templates = program.command("domain-templates").description("Browse and apply domain templates").addHelpText(
4566
4712
  "after",
4567
- dedent18`
4713
+ dedent19`
4568
4714
 
4569
4715
  A domain template is an industry-specific starter pack of fact
4570
4716
  definitions and sample rules. Applying one provisions a ready-to-use
@@ -4612,7 +4758,7 @@ function registerDomainTemplateCommands(program) {
4612
4758
  });
4613
4759
  templates.command("preview").description("Preview what a domain template provisions").requiredOption("--template <key>", "Domain template key (e.g. ECOMMERCE)").addHelpText(
4614
4760
  "after",
4615
- dedent18`
4761
+ dedent19`
4616
4762
 
4617
4763
  Read-only dry run — shows the fact definitions and sample rules the
4618
4764
  template will create. Nothing is provisioned.
@@ -4641,7 +4787,7 @@ function registerDomainTemplateCommands(program) {
4641
4787
  });
4642
4788
  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(
4643
4789
  "after",
4644
- dedent18`
4790
+ dedent19`
4645
4791
 
4646
4792
  Creates the template's fact definitions and a new DRAFT policy group
4647
4793
  populated with its sample rules. Existing facts are skipped — apply is
@@ -4716,6 +4862,7 @@ function createCli() {
4716
4862
  registerDomainTemplateCommands(program);
4717
4863
  registerDeployCommands(program);
4718
4864
  registerAnalyticsCommands(program);
4865
+ registerProfileCommands(program);
4719
4866
  registerHistoryCommands(program);
4720
4867
  registerReplayCommands(program);
4721
4868
  registerProvenanceCommands(program);