@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 +295 -148
- package/dist/mcp/register.js +126 -77
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2183,13 +2183,140 @@ function resolveBody(opts) {
|
|
|
2183
2183
|
return {};
|
|
2184
2184
|
}
|
|
2185
2185
|
|
|
2186
|
-
// src/commands/
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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:
|
|
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
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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/
|
|
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:
|
|
4071
|
-
candidateVersionId:
|
|
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:
|
|
4083
|
-
from:
|
|
4084
|
-
to:
|
|
4085
|
-
maxRecords:
|
|
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:
|
|
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:
|
|
4108
|
-
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:
|
|
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
|
|
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:
|
|
4136
|
-
size:
|
|
4137
|
-
traceId:
|
|
4138
|
-
groupId:
|
|
4139
|
-
versionId:
|
|
4140
|
-
status:
|
|
4141
|
-
startDate:
|
|
4142
|
-
endDate:
|
|
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:
|
|
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:
|
|
4174
|
-
startDate:
|
|
4175
|
-
endDate:
|
|
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
|
|
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:
|
|
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:
|
|
4209
|
-
size:
|
|
4210
|
-
traceId:
|
|
4211
|
-
revealedBy:
|
|
4212
|
-
factKey:
|
|
4213
|
-
startDate:
|
|
4214
|
-
endDate:
|
|
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
|
|
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:
|
|
4239
|
-
size:
|
|
4240
|
-
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:
|
|
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:
|
|
4267
|
-
type:
|
|
4268
|
-
name:
|
|
4269
|
-
baseUrl:
|
|
4270
|
-
credential:
|
|
4271
|
-
additionalConfig:
|
|
4272
|
-
isActive:
|
|
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:
|
|
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
|
|
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:
|
|
4313
|
-
size:
|
|
4314
|
-
category:
|
|
4315
|
-
taskType:
|
|
4316
|
-
status:
|
|
4317
|
-
keyword:
|
|
4318
|
-
startDate:
|
|
4319
|
-
endDate:
|
|
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:
|
|
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:
|
|
4351
|
-
action:
|
|
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:
|
|
4365
|
-
action:
|
|
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
|
|
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:
|
|
4384
|
-
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:
|
|
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:
|
|
4410
|
-
name:
|
|
4411
|
-
webhookUrl:
|
|
4412
|
-
subscribedEvents:
|
|
4413
|
-
payloadFormat:
|
|
4414
|
-
secret:
|
|
4415
|
-
isActive:
|
|
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:
|
|
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:
|
|
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
|
|
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:
|
|
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:
|
|
4476
|
-
customName:
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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);
|