@lexq/cli 0.1.33 → 0.1.35
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 +469 -100
- package/dist/mcp/register.d.ts +1 -26
- package/dist/mcp/register.js +206 -69
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2327,13 +2327,240 @@ ${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
|
|
|
2327
2327
|
});
|
|
2328
2328
|
}
|
|
2329
2329
|
|
|
2330
|
-
// src/commands/
|
|
2330
|
+
// src/commands/replay.ts
|
|
2331
2331
|
import "commander";
|
|
2332
2332
|
import dedent10 from "dedent";
|
|
2333
|
+
function registerReplayCommands(program) {
|
|
2334
|
+
const replay = program.command("replay").description("Decision Replay").addHelpText(
|
|
2335
|
+
"after",
|
|
2336
|
+
dedent10`
|
|
2337
|
+
|
|
2338
|
+
Re-evaluate past production executions against a candidate version.
|
|
2339
|
+
|
|
2340
|
+
Commands:
|
|
2341
|
+
decision Replay one execution and show the decision diff (sync, free)
|
|
2342
|
+
start Submit a window replay job — blast radius (async, billed)
|
|
2343
|
+
list List replay job history
|
|
2344
|
+
get Poll a job's status, summary, and changed samples
|
|
2345
|
+
cancel Cancel a PENDING/RUNNING job
|
|
2346
|
+
|
|
2347
|
+
External effects (webhooks, notifications) are always mocked during replay.
|
|
2348
|
+
`
|
|
2349
|
+
);
|
|
2350
|
+
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(
|
|
2351
|
+
"after",
|
|
2352
|
+
dedent10`
|
|
2353
|
+
|
|
2354
|
+
Free of charge (TPS throttle only). Returns decisionChanged, effect
|
|
2355
|
+
changes, fired rules on both sides, and a determinism verdict.
|
|
2356
|
+
|
|
2357
|
+
Example:
|
|
2358
|
+
$ lexq replay decision --trace-id <tid> --version-id <vid>
|
|
2359
|
+
`
|
|
2360
|
+
).action(async (opts) => {
|
|
2361
|
+
try {
|
|
2362
|
+
const globalOpts = program.opts();
|
|
2363
|
+
const data = await apiRequest("POST", "replay/decisions", {
|
|
2364
|
+
apiKey: globalOpts.apiKey,
|
|
2365
|
+
baseUrl: globalOpts.baseUrl,
|
|
2366
|
+
dryRun: globalOpts.dryRun,
|
|
2367
|
+
verbose: globalOpts.verbose,
|
|
2368
|
+
body: { traceId: opts.traceId, candidateVersionId: opts.versionId }
|
|
2369
|
+
});
|
|
2370
|
+
printJson(data);
|
|
2371
|
+
} catch (error) {
|
|
2372
|
+
printError(error);
|
|
2373
|
+
process.exit(1);
|
|
2374
|
+
}
|
|
2375
|
+
});
|
|
2376
|
+
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(
|
|
2377
|
+
"after",
|
|
2378
|
+
dedent10`
|
|
2379
|
+
|
|
2380
|
+
Billed per replayed record (REPLAY metric). Poll with "lexq replay get".
|
|
2381
|
+
|
|
2382
|
+
Example:
|
|
2383
|
+
$ lexq replay start --version-id <vid> --from 2026-06-01 --to 2026-06-30
|
|
2384
|
+
`
|
|
2385
|
+
).action(async (opts) => {
|
|
2386
|
+
try {
|
|
2387
|
+
const globalOpts = program.opts();
|
|
2388
|
+
const body = {
|
|
2389
|
+
candidateVersionId: opts.versionId,
|
|
2390
|
+
from: opts.from,
|
|
2391
|
+
to: opts.to
|
|
2392
|
+
};
|
|
2393
|
+
if (opts.maxRecords) body.maxRecords = Number(opts.maxRecords);
|
|
2394
|
+
const data = await apiRequest("POST", "replay/jobs", {
|
|
2395
|
+
apiKey: globalOpts.apiKey,
|
|
2396
|
+
baseUrl: globalOpts.baseUrl,
|
|
2397
|
+
dryRun: globalOpts.dryRun,
|
|
2398
|
+
verbose: globalOpts.verbose,
|
|
2399
|
+
body
|
|
2400
|
+
});
|
|
2401
|
+
printJson(data);
|
|
2402
|
+
} catch (error) {
|
|
2403
|
+
printError(error);
|
|
2404
|
+
process.exit(1);
|
|
2405
|
+
}
|
|
2406
|
+
});
|
|
2407
|
+
replay.command("list").description("List replay jobs").option("--page <number>", "Page number", "0").option("--size <number>", "Page size", "20").action(async (opts) => {
|
|
2408
|
+
try {
|
|
2409
|
+
const globalOpts = program.opts();
|
|
2410
|
+
const format = globalOpts.format ?? "json";
|
|
2411
|
+
const data = await apiRequest("GET", "replay/jobs", {
|
|
2412
|
+
apiKey: globalOpts.apiKey,
|
|
2413
|
+
baseUrl: globalOpts.baseUrl,
|
|
2414
|
+
dryRun: globalOpts.dryRun,
|
|
2415
|
+
verbose: globalOpts.verbose,
|
|
2416
|
+
params: { page: opts.page, size: opts.size }
|
|
2417
|
+
});
|
|
2418
|
+
if (format === "table") {
|
|
2419
|
+
printTable(
|
|
2420
|
+
["Job", "Version", "Window", "Status", "Progress", "Changed", "At"],
|
|
2421
|
+
data.content.map((j) => [
|
|
2422
|
+
j.jobId.substring(0, 12),
|
|
2423
|
+
j.candidateVersionName ?? "\u2013",
|
|
2424
|
+
`${j.fromDate}~${j.toDate}`,
|
|
2425
|
+
j.status,
|
|
2426
|
+
`${j.progress}%`,
|
|
2427
|
+
`${j.changedCount}${j.capped ? " (capped)" : ""}`,
|
|
2428
|
+
j.createdAt.substring(0, 16)
|
|
2429
|
+
]),
|
|
2430
|
+
{ truncate: 24 }
|
|
2431
|
+
);
|
|
2432
|
+
console.log(`
|
|
2433
|
+
${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
|
|
2434
|
+
} else {
|
|
2435
|
+
printJson(data);
|
|
2436
|
+
}
|
|
2437
|
+
} catch (error) {
|
|
2438
|
+
printError(error);
|
|
2439
|
+
process.exit(1);
|
|
2440
|
+
}
|
|
2441
|
+
});
|
|
2442
|
+
replay.command("get").description("Get replay job status and results").requiredOption("--id <jobId>", "Replay job ID").action(async (opts) => {
|
|
2443
|
+
try {
|
|
2444
|
+
const globalOpts = program.opts();
|
|
2445
|
+
const data = await apiRequest("GET", `replay/jobs/${opts.id}`, {
|
|
2446
|
+
apiKey: globalOpts.apiKey,
|
|
2447
|
+
baseUrl: globalOpts.baseUrl,
|
|
2448
|
+
dryRun: globalOpts.dryRun,
|
|
2449
|
+
verbose: globalOpts.verbose
|
|
2450
|
+
});
|
|
2451
|
+
printJson(data);
|
|
2452
|
+
} catch (error) {
|
|
2453
|
+
printError(error);
|
|
2454
|
+
process.exit(1);
|
|
2455
|
+
}
|
|
2456
|
+
});
|
|
2457
|
+
replay.command("cancel").description("Cancel a PENDING/RUNNING replay job").requiredOption("--id <jobId>", "Replay job ID").action(async (opts) => {
|
|
2458
|
+
try {
|
|
2459
|
+
const globalOpts = program.opts();
|
|
2460
|
+
const data = await apiRequest("POST", `replay/jobs/${opts.id}/cancel`, {
|
|
2461
|
+
apiKey: globalOpts.apiKey,
|
|
2462
|
+
baseUrl: globalOpts.baseUrl,
|
|
2463
|
+
dryRun: globalOpts.dryRun,
|
|
2464
|
+
verbose: globalOpts.verbose
|
|
2465
|
+
});
|
|
2466
|
+
printJson(data);
|
|
2467
|
+
} catch (error) {
|
|
2468
|
+
printError(error);
|
|
2469
|
+
process.exit(1);
|
|
2470
|
+
}
|
|
2471
|
+
});
|
|
2472
|
+
}
|
|
2473
|
+
|
|
2474
|
+
// src/commands/provenance.ts
|
|
2475
|
+
import "commander";
|
|
2476
|
+
import dedent11 from "dedent";
|
|
2477
|
+
function registerProvenanceCommands(program) {
|
|
2478
|
+
const provenance = program.command("provenance").description("Decision Provenance").addHelpText(
|
|
2479
|
+
"after",
|
|
2480
|
+
dedent11`
|
|
2481
|
+
|
|
2482
|
+
Trace who authored, published, and deployed the rules behind a decision.
|
|
2483
|
+
|
|
2484
|
+
Commands:
|
|
2485
|
+
get Get the lineage of one decision (PII facts masked)
|
|
2486
|
+
reveal-audits List the PII reveal audit ledger (metadata only)
|
|
2487
|
+
`
|
|
2488
|
+
);
|
|
2489
|
+
provenance.command("get").description("Get decision lineage").requiredOption("--trace-id <traceId>", "Trace ID of the execution").action(async (opts) => {
|
|
2490
|
+
try {
|
|
2491
|
+
const globalOpts = program.opts();
|
|
2492
|
+
const data = await apiRequest("GET", `provenance/${opts.traceId}`, {
|
|
2493
|
+
apiKey: globalOpts.apiKey,
|
|
2494
|
+
baseUrl: globalOpts.baseUrl,
|
|
2495
|
+
dryRun: globalOpts.dryRun,
|
|
2496
|
+
verbose: globalOpts.verbose
|
|
2497
|
+
});
|
|
2498
|
+
printJson(data);
|
|
2499
|
+
} catch (error) {
|
|
2500
|
+
printError(error);
|
|
2501
|
+
process.exit(1);
|
|
2502
|
+
}
|
|
2503
|
+
});
|
|
2504
|
+
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(
|
|
2505
|
+
"after",
|
|
2506
|
+
dedent11`
|
|
2507
|
+
|
|
2508
|
+
Metadata only — revealed values are never stored or returned.
|
|
2509
|
+
|
|
2510
|
+
Example:
|
|
2511
|
+
$ lexq provenance reveal-audits --start-date 2026-07-01 --format table
|
|
2512
|
+
`
|
|
2513
|
+
).action(async (opts) => {
|
|
2514
|
+
try {
|
|
2515
|
+
const globalOpts = program.opts();
|
|
2516
|
+
const format = globalOpts.format ?? "json";
|
|
2517
|
+
const params = { page: opts.page, size: opts.size };
|
|
2518
|
+
if (opts.traceId) params.traceId = opts.traceId;
|
|
2519
|
+
if (opts.factKey) params.factKey = opts.factKey;
|
|
2520
|
+
if (opts.revealedBy) params.revealedBy = opts.revealedBy;
|
|
2521
|
+
if (opts.startDate) params.startDate = opts.startDate;
|
|
2522
|
+
if (opts.endDate) params.endDate = opts.endDate;
|
|
2523
|
+
const data = await apiRequest(
|
|
2524
|
+
"GET",
|
|
2525
|
+
"provenance/reveal-audits",
|
|
2526
|
+
{
|
|
2527
|
+
apiKey: globalOpts.apiKey,
|
|
2528
|
+
baseUrl: globalOpts.baseUrl,
|
|
2529
|
+
dryRun: globalOpts.dryRun,
|
|
2530
|
+
verbose: globalOpts.verbose,
|
|
2531
|
+
params
|
|
2532
|
+
}
|
|
2533
|
+
);
|
|
2534
|
+
if (format === "table") {
|
|
2535
|
+
printTable(
|
|
2536
|
+
["Revealed At", "By", "Fact Key", "Trace"],
|
|
2537
|
+
data.content.map((a) => [
|
|
2538
|
+
a.revealedAt.substring(0, 16),
|
|
2539
|
+
a.revealedByName,
|
|
2540
|
+
a.factKey,
|
|
2541
|
+
a.traceId.substring(0, 12)
|
|
2542
|
+
]),
|
|
2543
|
+
{ truncate: 24 }
|
|
2544
|
+
);
|
|
2545
|
+
console.log(`
|
|
2546
|
+
${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
|
|
2547
|
+
} else {
|
|
2548
|
+
printJson(data);
|
|
2549
|
+
}
|
|
2550
|
+
} catch (error) {
|
|
2551
|
+
printError(error);
|
|
2552
|
+
process.exit(1);
|
|
2553
|
+
}
|
|
2554
|
+
});
|
|
2555
|
+
}
|
|
2556
|
+
|
|
2557
|
+
// src/commands/integrations.ts
|
|
2558
|
+
import "commander";
|
|
2559
|
+
import dedent12 from "dedent";
|
|
2333
2560
|
function registerIntegrationCommands(program) {
|
|
2334
2561
|
const integrations = program.command("integrations").description("Manage external integrations").addHelpText(
|
|
2335
2562
|
"after",
|
|
2336
|
-
|
|
2563
|
+
dedent12`
|
|
2337
2564
|
|
|
2338
2565
|
Integrations connect rule actions to external services (webhooks, coupons,
|
|
2339
2566
|
points, notifications, CRM, messengers).
|
|
@@ -2403,7 +2630,7 @@ ${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
|
|
|
2403
2630
|
});
|
|
2404
2631
|
integrations.command("save").description("Create or update an integration").requiredOption("--json <body>", "Request body as JSON string").addHelpText(
|
|
2405
2632
|
"after",
|
|
2406
|
-
|
|
2633
|
+
dedent12`
|
|
2407
2634
|
|
|
2408
2635
|
Examples:
|
|
2409
2636
|
# Create
|
|
@@ -2453,7 +2680,7 @@ ${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
|
|
|
2453
2680
|
});
|
|
2454
2681
|
integrations.command("delete").description("Delete an integration").requiredOption("--id <integrationId>", "Integration ID").option("--force", "Skip confirmation prompt").addHelpText(
|
|
2455
2682
|
"after",
|
|
2456
|
-
|
|
2683
|
+
dedent12`
|
|
2457
2684
|
|
|
2458
2685
|
Rules referencing this integration will fail at execution time.
|
|
2459
2686
|
Use --force to skip confirmation.
|
|
@@ -2485,7 +2712,7 @@ ${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
|
|
|
2485
2712
|
});
|
|
2486
2713
|
integrations.command("config-spec").description("Get integration configuration field specs").addHelpText(
|
|
2487
2714
|
"after",
|
|
2488
|
-
|
|
2715
|
+
dedent12`
|
|
2489
2716
|
|
|
2490
2717
|
Shows required and optional configuration fields for each integration type.
|
|
2491
2718
|
|
|
@@ -2511,7 +2738,7 @@ ${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
|
|
|
2511
2738
|
|
|
2512
2739
|
// src/commands/logs.ts
|
|
2513
2740
|
import "commander";
|
|
2514
|
-
import
|
|
2741
|
+
import dedent13 from "dedent";
|
|
2515
2742
|
|
|
2516
2743
|
// src/types/enums.ts
|
|
2517
2744
|
var FailureStatus = ["PENDING", "RESOLVED", "IGNORED"];
|
|
@@ -2545,7 +2772,7 @@ var WebhookPayloadFormat = ["GENERIC", "SLACK"];
|
|
|
2545
2772
|
function registerLogCommands(program) {
|
|
2546
2773
|
const logs = program.command("logs").description("Failure logs").addHelpText(
|
|
2547
2774
|
"after",
|
|
2548
|
-
|
|
2775
|
+
dedent13`
|
|
2549
2776
|
|
|
2550
2777
|
System failure logs (DLQ) for background tasks — webhook calls, coupon issuance,
|
|
2551
2778
|
point operations, notifications, and platform event webhooks.
|
|
@@ -2562,7 +2789,7 @@ function registerLogCommands(program) {
|
|
|
2562
2789
|
);
|
|
2563
2790
|
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(
|
|
2564
2791
|
"after",
|
|
2565
|
-
|
|
2792
|
+
dedent13`
|
|
2566
2793
|
|
|
2567
2794
|
Examples:
|
|
2568
2795
|
$ lexq logs list --status PENDING --format table
|
|
@@ -2613,7 +2840,7 @@ ${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
|
|
|
2613
2840
|
});
|
|
2614
2841
|
logs.command("get").description("Get failure log detail").requiredOption("--id <logId>", "Log ID").addHelpText(
|
|
2615
2842
|
"after",
|
|
2616
|
-
|
|
2843
|
+
dedent13`
|
|
2617
2844
|
|
|
2618
2845
|
Includes the full payload that was used for the failed operation.
|
|
2619
2846
|
Use this to inspect what went wrong before deciding to RETRY or RESOLVE.
|
|
@@ -2635,7 +2862,7 @@ ${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
|
|
|
2635
2862
|
});
|
|
2636
2863
|
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(
|
|
2637
2864
|
"after",
|
|
2638
|
-
|
|
2865
|
+
dedent13`
|
|
2639
2866
|
|
|
2640
2867
|
Actions:
|
|
2641
2868
|
RETRY Re-execute the failed operation with the original payload
|
|
@@ -2667,7 +2894,7 @@ ${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
|
|
|
2667
2894
|
});
|
|
2668
2895
|
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(
|
|
2669
2896
|
"after",
|
|
2670
|
-
|
|
2897
|
+
dedent13`
|
|
2671
2898
|
|
|
2672
2899
|
Processes each log individually. Failures are skipped with a warning.
|
|
2673
2900
|
|
|
@@ -2695,11 +2922,11 @@ ${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
|
|
|
2695
2922
|
|
|
2696
2923
|
// src/commands/webhook-subscriptions.ts
|
|
2697
2924
|
import "commander";
|
|
2698
|
-
import
|
|
2925
|
+
import dedent14 from "dedent";
|
|
2699
2926
|
function registerWebhookSubscriptionCommands(program) {
|
|
2700
2927
|
const webhooks = program.command("webhook-subscriptions").description("Manage platform event webhook subscriptions").addHelpText(
|
|
2701
2928
|
"after",
|
|
2702
|
-
|
|
2929
|
+
dedent14`
|
|
2703
2930
|
|
|
2704
2931
|
Receive notifications when deployment lifecycle events occur
|
|
2705
2932
|
(publish, deploy, rollback, undeploy).
|
|
@@ -2773,7 +3000,7 @@ ${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
|
|
|
2773
3000
|
});
|
|
2774
3001
|
webhooks.command("save").description("Create or update a webhook subscription").requiredOption("--json <body>", "Request body as JSON string").addHelpText(
|
|
2775
3002
|
"after",
|
|
2776
|
-
|
|
3003
|
+
dedent14`
|
|
2777
3004
|
|
|
2778
3005
|
Examples:
|
|
2779
3006
|
# Create (Slack format)
|
|
@@ -2828,7 +3055,7 @@ ${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
|
|
|
2828
3055
|
});
|
|
2829
3056
|
webhooks.command("delete").description("Delete a webhook subscription").requiredOption("--id <subscriptionId>", "Subscription ID").option("--force", "Skip confirmation prompt").addHelpText(
|
|
2830
3057
|
"after",
|
|
2831
|
-
|
|
3058
|
+
dedent14`
|
|
2832
3059
|
|
|
2833
3060
|
Use --force to skip the confirmation prompt.
|
|
2834
3061
|
|
|
@@ -2862,7 +3089,7 @@ ${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
|
|
|
2862
3089
|
});
|
|
2863
3090
|
webhooks.command("test").description("Send a test event to verify webhook connectivity").requiredOption("--id <subscriptionId>", "Subscription ID").addHelpText(
|
|
2864
3091
|
"after",
|
|
2865
|
-
|
|
3092
|
+
dedent14`
|
|
2866
3093
|
|
|
2867
3094
|
Sends a test event to the webhook URL and reports the HTTP status code.
|
|
2868
3095
|
Does not record failures in the failure log.
|
|
@@ -2898,7 +3125,7 @@ ${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
|
|
|
2898
3125
|
|
|
2899
3126
|
// src/commands/serve.ts
|
|
2900
3127
|
import "commander";
|
|
2901
|
-
import
|
|
3128
|
+
import dedent17 from "dedent";
|
|
2902
3129
|
|
|
2903
3130
|
// src/mcp/server.ts
|
|
2904
3131
|
import { readFileSync as readFileSync3 } from "fs";
|
|
@@ -3220,7 +3447,7 @@ function registerVersionTools(server, callApi) {
|
|
|
3220
3447
|
|
|
3221
3448
|
// src/mcp/tools/rules.ts
|
|
3222
3449
|
import { z as z3 } from "zod";
|
|
3223
|
-
import
|
|
3450
|
+
import dedent15 from "dedent";
|
|
3224
3451
|
function registerRuleTools(server, callApi) {
|
|
3225
3452
|
server.registerTool(
|
|
3226
3453
|
"lexq_rules_list",
|
|
@@ -3251,7 +3478,7 @@ function registerRuleTools(server, callApi) {
|
|
|
3251
3478
|
"lexq_rules_create",
|
|
3252
3479
|
{
|
|
3253
3480
|
title: "Create Rule",
|
|
3254
|
-
description:
|
|
3481
|
+
description: dedent15`
|
|
3255
3482
|
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.
|
|
3256
3483
|
|
|
3257
3484
|
Before creating rules with new fact keys, call lexq_facts_list to check existing facts.
|
|
@@ -3593,13 +3820,13 @@ function registerDeployTools(server, callApi) {
|
|
|
3593
3820
|
|
|
3594
3821
|
// src/mcp/tools/analytics.ts
|
|
3595
3822
|
import { z as z6 } from "zod";
|
|
3596
|
-
import
|
|
3823
|
+
import dedent16 from "dedent";
|
|
3597
3824
|
function registerAnalyticsTools(server, callApi) {
|
|
3598
3825
|
server.registerTool(
|
|
3599
3826
|
"lexq_dry_run",
|
|
3600
3827
|
{
|
|
3601
3828
|
title: "Dry Run",
|
|
3602
|
-
description:
|
|
3829
|
+
description: dedent16`
|
|
3603
3830
|
Execute a single dry run against a version. Tests how rules evaluate given input facts without side effects.
|
|
3604
3831
|
|
|
3605
3832
|
Returns:
|
|
@@ -3629,7 +3856,7 @@ function registerAnalyticsTools(server, callApi) {
|
|
|
3629
3856
|
"lexq_dry_run_compare",
|
|
3630
3857
|
{
|
|
3631
3858
|
title: "Dry Run Compare",
|
|
3632
|
-
description:
|
|
3859
|
+
description: dedent16`
|
|
3633
3860
|
Compare dry run results between two versions using the same input facts. Useful for validating changes.
|
|
3634
3861
|
|
|
3635
3862
|
Returns:
|
|
@@ -3665,22 +3892,33 @@ function registerAnalyticsTools(server, callApi) {
|
|
|
3665
3892
|
"lexq_simulation_start",
|
|
3666
3893
|
{
|
|
3667
3894
|
title: "Start Simulation",
|
|
3668
|
-
description:
|
|
3669
|
-
Start an Impact Simulation against historical or
|
|
3895
|
+
description: dedent16`
|
|
3896
|
+
Start an Impact Simulation against historical, uploaded, or inline data.
|
|
3897
|
+
|
|
3898
|
+
dataset.type and dataset.source are BOTH required, and must be paired:
|
|
3899
|
+
HISTORICAL → source EXECUTION_LOGS, with dataset.from / dataset.to (yyyy-MM-dd)
|
|
3900
|
+
UPLOADED → source S3_BUCKET, with dataset.path (the path returned by lexq_dataset_upload)
|
|
3901
|
+
MANUAL → source REQUEST_BODY, with dataset.manualData (array of fact records)
|
|
3670
3902
|
|
|
3671
|
-
dataset.type: "HISTORICAL" or "UPLOADED"
|
|
3672
|
-
dataset.source (when HISTORICAL): "EXECUTION_LOGS"
|
|
3673
|
-
dataset.from / dataset.to: date range (yyyy-MM-dd, when HISTORICAL)
|
|
3674
3903
|
options.maxRecords: number (max 100000, default 10000)
|
|
3675
|
-
options.baselinePolicyVersionId: uuid (optional, for comparison)
|
|
3904
|
+
options.baselinePolicyVersionId: uuid (optional, for baseline comparison)
|
|
3676
3905
|
options.includeRuleStats: boolean
|
|
3906
|
+
options.metricConfig: optional — omit for plain execution count. To aggregate a fact, pass
|
|
3907
|
+
{ "targetVariable": "<fact>", "aggregationType": "COUNT" | "SUM" | "AVG" }
|
|
3677
3908
|
|
|
3678
|
-
Example
|
|
3909
|
+
Example (uploaded dataset):
|
|
3679
3910
|
{
|
|
3680
3911
|
"policyVersionId": "<uuid>",
|
|
3681
|
-
"dataset": { "type": "
|
|
3912
|
+
"dataset": { "type": "UPLOADED", "source": "S3_BUCKET", "path": "<path from lexq_dataset_upload>" },
|
|
3682
3913
|
"options": { "baselinePolicyVersionId": "<uuid>", "includeRuleStats": true, "maxRecords": 10000 }
|
|
3683
3914
|
}
|
|
3915
|
+
|
|
3916
|
+
Example (historical):
|
|
3917
|
+
{
|
|
3918
|
+
"policyVersionId": "<uuid>",
|
|
3919
|
+
"dataset": { "type": "HISTORICAL", "source": "EXECUTION_LOGS", "from": "2026-01-01", "to": "2026-01-31" },
|
|
3920
|
+
"options": { "baselinePolicyVersionId": "<uuid>", "includeRuleStats": true }
|
|
3921
|
+
}
|
|
3684
3922
|
`,
|
|
3685
3923
|
inputSchema: {
|
|
3686
3924
|
body: z6.string().describe("JSON string of SimulationRequest")
|
|
@@ -3752,10 +3990,12 @@ function registerAnalyticsTools(server, callApi) {
|
|
|
3752
3990
|
"lexq_dataset_upload",
|
|
3753
3991
|
{
|
|
3754
3992
|
title: "Upload Dataset",
|
|
3755
|
-
description:
|
|
3993
|
+
description: dedent16`
|
|
3756
3994
|
Upload inline CSV or JSON content as a simulation dataset.
|
|
3757
|
-
The content is uploaded to S3 and a path is returned.
|
|
3758
|
-
|
|
3995
|
+
The content is uploaded to S3 and a path is returned in the "path" field.
|
|
3996
|
+
|
|
3997
|
+
To use the returned path in lexq_simulation_start, set:
|
|
3998
|
+
dataset: { "type": "UPLOADED", "source": "S3_BUCKET", "path": "<returned path>" }
|
|
3759
3999
|
|
|
3760
4000
|
CSV example:
|
|
3761
4001
|
user_id,payment_amount
|
|
@@ -3769,9 +4009,25 @@ function registerAnalyticsTools(server, callApi) {
|
|
|
3769
4009
|
filename: z6.string().default("dataset.csv").describe("Filename with extension (.csv or .json)")
|
|
3770
4010
|
}
|
|
3771
4011
|
},
|
|
3772
|
-
async ({ content, filename }) =>
|
|
3773
|
-
|
|
3774
|
-
|
|
4012
|
+
async ({ content, filename }) => {
|
|
4013
|
+
const result = await callApi("POST", "analytics/datasets/upload", {
|
|
4014
|
+
upload: { content, filename, fieldName: "file" }
|
|
4015
|
+
});
|
|
4016
|
+
if (!result.isError) {
|
|
4017
|
+
try {
|
|
4018
|
+
const uploaded = JSON.parse(result.content[0]?.text ?? "{}");
|
|
4019
|
+
if (uploaded.path) {
|
|
4020
|
+
const dataset = { type: "UPLOADED", source: "S3_BUCKET", path: uploaded.path };
|
|
4021
|
+
result.content.push({
|
|
4022
|
+
type: "text",
|
|
4023
|
+
text: "Ready-to-use dataset block for lexq_simulation_start:\n" + JSON.stringify({ dataset }, null, 2)
|
|
4024
|
+
});
|
|
4025
|
+
}
|
|
4026
|
+
} catch {
|
|
4027
|
+
}
|
|
4028
|
+
}
|
|
4029
|
+
return result;
|
|
4030
|
+
}
|
|
3775
4031
|
);
|
|
3776
4032
|
server.registerTool(
|
|
3777
4033
|
"lexq_dataset_template",
|
|
@@ -3790,8 +4046,73 @@ function registerAnalyticsTools(server, callApi) {
|
|
|
3790
4046
|
);
|
|
3791
4047
|
}
|
|
3792
4048
|
|
|
3793
|
-
// src/mcp/tools/
|
|
4049
|
+
// src/mcp/tools/replay.ts
|
|
3794
4050
|
import { z as z7 } from "zod";
|
|
4051
|
+
function registerReplayTools(server, callApi) {
|
|
4052
|
+
server.registerTool(
|
|
4053
|
+
"lexq_replay_decision",
|
|
4054
|
+
{
|
|
4055
|
+
title: "Replay a Decision",
|
|
4056
|
+
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.",
|
|
4057
|
+
inputSchema: {
|
|
4058
|
+
traceId: z7.string().describe("Trace ID of the past execution to replay"),
|
|
4059
|
+
candidateVersionId: z7.string().uuid().describe("Version to re-evaluate against")
|
|
4060
|
+
}
|
|
4061
|
+
},
|
|
4062
|
+
async ({ traceId, candidateVersionId }) => callApi("POST", "replay/decisions", { body: { traceId, candidateVersionId } })
|
|
4063
|
+
);
|
|
4064
|
+
server.registerTool(
|
|
4065
|
+
"lexq_replay_start",
|
|
4066
|
+
{
|
|
4067
|
+
title: "Start Window Replay (Blast Radius)",
|
|
4068
|
+
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.",
|
|
4069
|
+
inputSchema: {
|
|
4070
|
+
candidateVersionId: z7.string().uuid().describe("Version to re-evaluate against"),
|
|
4071
|
+
from: z7.string().describe("Window start date (yyyy-MM-dd)"),
|
|
4072
|
+
to: z7.string().describe("Window end date (yyyy-MM-dd)"),
|
|
4073
|
+
maxRecords: z7.number().int().min(1).optional().describe("Sample cap (server default applies; hard cap 50k)")
|
|
4074
|
+
}
|
|
4075
|
+
},
|
|
4076
|
+
async ({ candidateVersionId, from, to, maxRecords }) => callApi("POST", "replay/jobs", { body: { candidateVersionId, from, to, maxRecords } })
|
|
4077
|
+
);
|
|
4078
|
+
server.registerTool(
|
|
4079
|
+
"lexq_replay_status",
|
|
4080
|
+
{
|
|
4081
|
+
title: "Get Replay Job Status",
|
|
4082
|
+
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.",
|
|
4083
|
+
inputSchema: {
|
|
4084
|
+
jobId: z7.string().describe("Replay job ID from lexq_replay_start")
|
|
4085
|
+
}
|
|
4086
|
+
},
|
|
4087
|
+
async ({ jobId }) => callApi("GET", `replay/jobs/${jobId}`)
|
|
4088
|
+
);
|
|
4089
|
+
server.registerTool(
|
|
4090
|
+
"lexq_replay_list",
|
|
4091
|
+
{
|
|
4092
|
+
title: "List Replay Jobs",
|
|
4093
|
+
description: "List window replay job history (reverse-chronological). Lightweight items \u2014 use lexq_replay_status for summary and changed samples.",
|
|
4094
|
+
inputSchema: {
|
|
4095
|
+
page: z7.number().int().min(0).default(0).describe("Page number"),
|
|
4096
|
+
size: z7.number().int().min(1).max(100).default(20).describe("Page size")
|
|
4097
|
+
}
|
|
4098
|
+
},
|
|
4099
|
+
async ({ page, size }) => callApi("GET", "replay/jobs", { params: paginationParams(page, size) })
|
|
4100
|
+
);
|
|
4101
|
+
server.registerTool(
|
|
4102
|
+
"lexq_replay_cancel",
|
|
4103
|
+
{
|
|
4104
|
+
title: "Cancel Replay Job",
|
|
4105
|
+
description: "Cooperatively cancel a PENDING or RUNNING window replay job. Other states are rejected. VIEWER role cannot cancel.",
|
|
4106
|
+
inputSchema: {
|
|
4107
|
+
jobId: z7.string().describe("Replay job ID")
|
|
4108
|
+
}
|
|
4109
|
+
},
|
|
4110
|
+
async ({ jobId }) => callApi("POST", `replay/jobs/${jobId}/cancel`)
|
|
4111
|
+
);
|
|
4112
|
+
}
|
|
4113
|
+
|
|
4114
|
+
// src/mcp/tools/history.ts
|
|
4115
|
+
import { z as z8 } from "zod";
|
|
3795
4116
|
function registerHistoryTools(server, callApi) {
|
|
3796
4117
|
server.registerTool(
|
|
3797
4118
|
"lexq_history_list",
|
|
@@ -3799,14 +4120,14 @@ function registerHistoryTools(server, callApi) {
|
|
|
3799
4120
|
title: "List Execution History",
|
|
3800
4121
|
description: "List policy execution history. Shows trace ID, group, version, status, match result, and latency.",
|
|
3801
4122
|
inputSchema: {
|
|
3802
|
-
page:
|
|
3803
|
-
size:
|
|
3804
|
-
traceId:
|
|
3805
|
-
groupId:
|
|
3806
|
-
versionId:
|
|
3807
|
-
status:
|
|
3808
|
-
startDate:
|
|
3809
|
-
endDate:
|
|
4123
|
+
page: z8.number().int().min(0).default(0).describe("Page number"),
|
|
4124
|
+
size: z8.number().int().min(1).max(100).default(20).describe("Page size"),
|
|
4125
|
+
traceId: z8.string().optional().describe("Filter by trace ID"),
|
|
4126
|
+
groupId: z8.string().uuid().optional().describe("Filter by policy group"),
|
|
4127
|
+
versionId: z8.string().uuid().optional().describe("Filter by version"),
|
|
4128
|
+
status: z8.enum(["SUCCESS", "NO_MATCH", "ERROR", "TIMEOUT"]).optional().describe("Filter by execution status"),
|
|
4129
|
+
startDate: z8.string().optional().describe("Start date (yyyy-MM-dd)"),
|
|
4130
|
+
endDate: z8.string().optional().describe("End date (yyyy-MM-dd)")
|
|
3810
4131
|
}
|
|
3811
4132
|
},
|
|
3812
4133
|
async ({ page, size, traceId, groupId, versionId, status, startDate, endDate }) => {
|
|
@@ -3826,7 +4147,7 @@ function registerHistoryTools(server, callApi) {
|
|
|
3826
4147
|
title: "Get Execution Detail",
|
|
3827
4148
|
description: "Get full execution detail including inputFacts, mutatedFacts, generatedVariables, executionTraces, and decisionTraces.",
|
|
3828
4149
|
inputSchema: {
|
|
3829
|
-
traceId:
|
|
4150
|
+
traceId: z8.string().describe("Trace ID from execution history")
|
|
3830
4151
|
}
|
|
3831
4152
|
},
|
|
3832
4153
|
async ({ traceId }) => callApi("GET", `execution/history/${traceId}`)
|
|
@@ -3837,9 +4158,9 @@ function registerHistoryTools(server, callApi) {
|
|
|
3837
4158
|
title: "Execution Statistics",
|
|
3838
4159
|
description: "Get execution KPIs: total executions, success/failure counts, success rate, and average latency.",
|
|
3839
4160
|
inputSchema: {
|
|
3840
|
-
groupId:
|
|
3841
|
-
startDate:
|
|
3842
|
-
endDate:
|
|
4161
|
+
groupId: z8.string().uuid().optional().describe("Filter by policy group"),
|
|
4162
|
+
startDate: z8.string().optional().describe("Start date (yyyy-MM-dd)"),
|
|
4163
|
+
endDate: z8.string().optional().describe("End date (yyyy-MM-dd)")
|
|
3843
4164
|
}
|
|
3844
4165
|
},
|
|
3845
4166
|
async ({ groupId, startDate, endDate }) => {
|
|
@@ -3852,8 +4173,49 @@ function registerHistoryTools(server, callApi) {
|
|
|
3852
4173
|
);
|
|
3853
4174
|
}
|
|
3854
4175
|
|
|
4176
|
+
// src/mcp/tools/provenance.ts
|
|
4177
|
+
import { z as z9 } from "zod";
|
|
4178
|
+
function registerProvenanceTools(server, callApi) {
|
|
4179
|
+
server.registerTool(
|
|
4180
|
+
"lexq_provenance_get",
|
|
4181
|
+
{
|
|
4182
|
+
title: "Get Decision Provenance",
|
|
4183
|
+
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.",
|
|
4184
|
+
inputSchema: {
|
|
4185
|
+
traceId: z9.string().describe("Trace ID of the execution")
|
|
4186
|
+
}
|
|
4187
|
+
},
|
|
4188
|
+
async ({ traceId }) => callApi("GET", `provenance/${traceId}`)
|
|
4189
|
+
);
|
|
4190
|
+
server.registerTool(
|
|
4191
|
+
"lexq_pii_reveals_list",
|
|
4192
|
+
{
|
|
4193
|
+
title: "List PII Reveal Audits",
|
|
4194
|
+
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.",
|
|
4195
|
+
inputSchema: {
|
|
4196
|
+
page: z9.number().int().min(0).default(0).describe("Page number"),
|
|
4197
|
+
size: z9.number().int().min(1).max(100).default(20).describe("Page size"),
|
|
4198
|
+
traceId: z9.string().optional().describe("Filter by trace ID (exact match)"),
|
|
4199
|
+
revealedBy: z9.string().optional().describe("Filter by operator ID (exact match)"),
|
|
4200
|
+
factKey: z9.string().optional().describe("Filter by fact key (partial match, case-insensitive)"),
|
|
4201
|
+
startDate: z9.string().optional().describe("Start date (yyyy-MM-dd)"),
|
|
4202
|
+
endDate: z9.string().optional().describe("End date (yyyy-MM-dd)")
|
|
4203
|
+
}
|
|
4204
|
+
},
|
|
4205
|
+
async ({ page, size, traceId, revealedBy, factKey, startDate, endDate }) => {
|
|
4206
|
+
const params = paginationParams(page, size);
|
|
4207
|
+
if (traceId) params.traceId = traceId;
|
|
4208
|
+
if (revealedBy) params.revealedBy = revealedBy;
|
|
4209
|
+
if (factKey) params.factKey = factKey;
|
|
4210
|
+
if (startDate) params.startDate = startDate;
|
|
4211
|
+
if (endDate) params.endDate = endDate;
|
|
4212
|
+
return callApi("GET", "provenance/reveal-audits", { params });
|
|
4213
|
+
}
|
|
4214
|
+
);
|
|
4215
|
+
}
|
|
4216
|
+
|
|
3855
4217
|
// src/mcp/tools/integrations.ts
|
|
3856
|
-
import { z as
|
|
4218
|
+
import { z as z10 } from "zod";
|
|
3857
4219
|
function registerIntegrationTools(server, callApi) {
|
|
3858
4220
|
server.registerTool(
|
|
3859
4221
|
"lexq_integrations_list",
|
|
@@ -3861,9 +4223,9 @@ function registerIntegrationTools(server, callApi) {
|
|
|
3861
4223
|
title: "List Integrations",
|
|
3862
4224
|
description: "List all external integrations (webhooks, CRM, notification, etc.).",
|
|
3863
4225
|
inputSchema: {
|
|
3864
|
-
page:
|
|
3865
|
-
size:
|
|
3866
|
-
type:
|
|
4226
|
+
page: z10.number().int().min(0).default(0).describe("Page number"),
|
|
4227
|
+
size: z10.number().int().min(1).max(100).default(20).describe("Page size"),
|
|
4228
|
+
type: z10.enum(["COUPON", "POINT", "NOTIFICATION", "CRM", "MESSENGER", "WEBHOOK"]).optional().describe("Filter by integration type")
|
|
3867
4229
|
}
|
|
3868
4230
|
},
|
|
3869
4231
|
async ({ page, size, type }) => {
|
|
@@ -3878,7 +4240,7 @@ function registerIntegrationTools(server, callApi) {
|
|
|
3878
4240
|
title: "Get Integration",
|
|
3879
4241
|
description: "Get integration detail by ID.",
|
|
3880
4242
|
inputSchema: {
|
|
3881
|
-
integrationId:
|
|
4243
|
+
integrationId: z10.string().uuid().describe("Integration ID")
|
|
3882
4244
|
}
|
|
3883
4245
|
},
|
|
3884
4246
|
async ({ integrationId }) => callApi("GET", `integrations/${integrationId}`)
|
|
@@ -3889,13 +4251,13 @@ function registerIntegrationTools(server, callApi) {
|
|
|
3889
4251
|
title: "Save Integration",
|
|
3890
4252
|
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.",
|
|
3891
4253
|
inputSchema: {
|
|
3892
|
-
id:
|
|
3893
|
-
type:
|
|
3894
|
-
name:
|
|
3895
|
-
baseUrl:
|
|
3896
|
-
credential:
|
|
3897
|
-
additionalConfig:
|
|
3898
|
-
isActive:
|
|
4254
|
+
id: z10.string().uuid().optional().describe("Integration ID (omit to create, provide to update)"),
|
|
4255
|
+
type: z10.enum(["COUPON", "POINT", "NOTIFICATION", "CRM", "MESSENGER", "WEBHOOK"]).describe("Integration type"),
|
|
4256
|
+
name: z10.string().describe("Integration name"),
|
|
4257
|
+
baseUrl: z10.string().describe("Base URL of the external service"),
|
|
4258
|
+
credential: z10.string().optional().describe("API key or token for the service"),
|
|
4259
|
+
additionalConfig: z10.string().optional().describe("JSON string of additional config key-value pairs"),
|
|
4260
|
+
isActive: z10.boolean().default(true).describe("Whether the integration is active")
|
|
3899
4261
|
}
|
|
3900
4262
|
},
|
|
3901
4263
|
async ({ additionalConfig, ...rest }) => {
|
|
@@ -3910,7 +4272,7 @@ function registerIntegrationTools(server, callApi) {
|
|
|
3910
4272
|
title: "Delete Integration",
|
|
3911
4273
|
description: "Delete an integration by ID.",
|
|
3912
4274
|
inputSchema: {
|
|
3913
|
-
integrationId:
|
|
4275
|
+
integrationId: z10.string().uuid().describe("Integration ID")
|
|
3914
4276
|
}
|
|
3915
4277
|
},
|
|
3916
4278
|
async ({ integrationId }) => callApi("DELETE", `integrations/${integrationId}`)
|
|
@@ -3927,7 +4289,7 @@ function registerIntegrationTools(server, callApi) {
|
|
|
3927
4289
|
}
|
|
3928
4290
|
|
|
3929
4291
|
// src/mcp/tools/logs.ts
|
|
3930
|
-
import { z as
|
|
4292
|
+
import { z as z11 } from "zod";
|
|
3931
4293
|
function registerLogTools(server, callApi) {
|
|
3932
4294
|
server.registerTool(
|
|
3933
4295
|
"lexq_logs_list",
|
|
@@ -3935,14 +4297,14 @@ function registerLogTools(server, callApi) {
|
|
|
3935
4297
|
title: "List Failure Logs",
|
|
3936
4298
|
description: "List system failure logs from background tasks (webhook calls, coupon issuance, etc.).",
|
|
3937
4299
|
inputSchema: {
|
|
3938
|
-
page:
|
|
3939
|
-
size:
|
|
3940
|
-
category:
|
|
3941
|
-
taskType:
|
|
3942
|
-
status:
|
|
3943
|
-
keyword:
|
|
3944
|
-
startDate:
|
|
3945
|
-
endDate:
|
|
4300
|
+
page: z11.number().int().min(0).default(0).describe("Page number"),
|
|
4301
|
+
size: z11.number().int().min(1).max(100).default(20).describe("Page size"),
|
|
4302
|
+
category: z11.enum(TaskCategory).optional().describe("Task category"),
|
|
4303
|
+
taskType: z11.enum(TaskType).optional().describe("Task type"),
|
|
4304
|
+
status: z11.enum(FailureStatus).optional().describe("Log status"),
|
|
4305
|
+
keyword: z11.string().optional().describe("Search in refId, refSubId, errorMessage"),
|
|
4306
|
+
startDate: z11.string().optional().describe("Start date (yyyy-MM-dd)"),
|
|
4307
|
+
endDate: z11.string().optional().describe("End date (yyyy-MM-dd)")
|
|
3946
4308
|
}
|
|
3947
4309
|
},
|
|
3948
4310
|
async ({ page, size, category, taskType, status, keyword, startDate, endDate }) => {
|
|
@@ -3962,7 +4324,7 @@ function registerLogTools(server, callApi) {
|
|
|
3962
4324
|
title: "Get Failure Log",
|
|
3963
4325
|
description: "Get failure log detail by ID.",
|
|
3964
4326
|
inputSchema: {
|
|
3965
|
-
logId:
|
|
4327
|
+
logId: z11.string().uuid().describe("Failure log ID")
|
|
3966
4328
|
}
|
|
3967
4329
|
},
|
|
3968
4330
|
async ({ logId }) => callApi("GET", `failure-logs/${logId}`)
|
|
@@ -3973,8 +4335,8 @@ function registerLogTools(server, callApi) {
|
|
|
3973
4335
|
title: "Process Failure Log",
|
|
3974
4336
|
description: "Process a single failure log: RETRY (re-execute with original payload), RESOLVE (mark as manually fixed), or IGNORE (skip intentionally).",
|
|
3975
4337
|
inputSchema: {
|
|
3976
|
-
logId:
|
|
3977
|
-
action:
|
|
4338
|
+
logId: z11.string().uuid().describe("Failure log ID"),
|
|
4339
|
+
action: z11.enum(FailureAction).describe("Action to take")
|
|
3978
4340
|
}
|
|
3979
4341
|
},
|
|
3980
4342
|
async ({ logId, action }) => callApi("POST", `failure-logs/${logId}/actions`, {
|
|
@@ -3987,8 +4349,8 @@ function registerLogTools(server, callApi) {
|
|
|
3987
4349
|
title: "Bulk Process Failure Logs",
|
|
3988
4350
|
description: "Process multiple failure logs at once. Provide an array of log IDs and the action.",
|
|
3989
4351
|
inputSchema: {
|
|
3990
|
-
logIds:
|
|
3991
|
-
action:
|
|
4352
|
+
logIds: z11.array(z11.string().uuid()).describe("Array of failure log IDs"),
|
|
4353
|
+
action: z11.enum(FailureAction).describe("Action to apply to all logs")
|
|
3992
4354
|
}
|
|
3993
4355
|
},
|
|
3994
4356
|
async ({ logIds, action }) => callApi("POST", "failure-logs/bulk-actions", {
|
|
@@ -3998,7 +4360,7 @@ function registerLogTools(server, callApi) {
|
|
|
3998
4360
|
}
|
|
3999
4361
|
|
|
4000
4362
|
// src/mcp/tools/webhook-subscriptions.ts
|
|
4001
|
-
import { z as
|
|
4363
|
+
import { z as z12 } from "zod";
|
|
4002
4364
|
function registerWebhookSubscriptionTools(server, callApi) {
|
|
4003
4365
|
server.registerTool(
|
|
4004
4366
|
"lexq_webhook_subscriptions_list",
|
|
@@ -4006,8 +4368,8 @@ function registerWebhookSubscriptionTools(server, callApi) {
|
|
|
4006
4368
|
title: "List Webhook Subscriptions",
|
|
4007
4369
|
description: "List platform event webhook subscriptions. These receive deployment lifecycle notifications (publish, deploy, rollback, undeploy).",
|
|
4008
4370
|
inputSchema: {
|
|
4009
|
-
page:
|
|
4010
|
-
size:
|
|
4371
|
+
page: z12.number().int().min(0).default(0).describe("Page number"),
|
|
4372
|
+
size: z12.number().int().min(1).max(100).default(20).describe("Page size")
|
|
4011
4373
|
}
|
|
4012
4374
|
},
|
|
4013
4375
|
async ({ page, size }) => {
|
|
@@ -4021,7 +4383,7 @@ function registerWebhookSubscriptionTools(server, callApi) {
|
|
|
4021
4383
|
title: "Get Webhook Subscription",
|
|
4022
4384
|
description: "Get webhook subscription detail by ID.",
|
|
4023
4385
|
inputSchema: {
|
|
4024
|
-
id:
|
|
4386
|
+
id: z12.string().uuid().describe("Webhook subscription ID")
|
|
4025
4387
|
}
|
|
4026
4388
|
},
|
|
4027
4389
|
async ({ id }) => callApi("GET", `webhook-subscriptions/${id}`)
|
|
@@ -4032,13 +4394,13 @@ function registerWebhookSubscriptionTools(server, callApi) {
|
|
|
4032
4394
|
title: "Save Webhook Subscription",
|
|
4033
4395
|
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": "..."}).',
|
|
4034
4396
|
inputSchema: {
|
|
4035
|
-
id:
|
|
4036
|
-
name:
|
|
4037
|
-
webhookUrl:
|
|
4038
|
-
subscribedEvents:
|
|
4039
|
-
payloadFormat:
|
|
4040
|
-
secret:
|
|
4041
|
-
isActive:
|
|
4397
|
+
id: z12.string().uuid().optional().describe("Subscription ID (omit to create, provide to update)"),
|
|
4398
|
+
name: z12.string().min(1).describe("Subscription name (unique per tenant)"),
|
|
4399
|
+
webhookUrl: z12.string().url().describe("Webhook endpoint URL"),
|
|
4400
|
+
subscribedEvents: z12.array(z12.enum(PlatformEventType)).min(1).describe("Events to subscribe to"),
|
|
4401
|
+
payloadFormat: z12.enum(WebhookPayloadFormat).optional().default("GENERIC").describe("Payload format"),
|
|
4402
|
+
secret: z12.string().optional().describe("HMAC-SHA256 signing secret"),
|
|
4403
|
+
isActive: z12.boolean().optional().default(true).describe("Whether the subscription is active")
|
|
4042
4404
|
}
|
|
4043
4405
|
},
|
|
4044
4406
|
async ({ ...body }) => callApi("POST", "webhook-subscriptions", { body })
|
|
@@ -4049,7 +4411,7 @@ function registerWebhookSubscriptionTools(server, callApi) {
|
|
|
4049
4411
|
title: "Delete Webhook Subscription",
|
|
4050
4412
|
description: "Delete a webhook subscription by ID.",
|
|
4051
4413
|
inputSchema: {
|
|
4052
|
-
id:
|
|
4414
|
+
id: z12.string().uuid().describe("Webhook subscription ID")
|
|
4053
4415
|
}
|
|
4054
4416
|
},
|
|
4055
4417
|
async ({ id }) => callApi("DELETE", `webhook-subscriptions/${id}`)
|
|
@@ -4060,7 +4422,7 @@ function registerWebhookSubscriptionTools(server, callApi) {
|
|
|
4060
4422
|
title: "Test Webhook Subscription",
|
|
4061
4423
|
description: "Send a test event to verify webhook connectivity. Returns the HTTP status code and success/failure message.",
|
|
4062
4424
|
inputSchema: {
|
|
4063
|
-
id:
|
|
4425
|
+
id: z12.string().uuid().describe("Webhook subscription ID")
|
|
4064
4426
|
}
|
|
4065
4427
|
},
|
|
4066
4428
|
async ({ id }) => callApi("POST", `webhook-subscriptions/${id}/test`)
|
|
@@ -4068,7 +4430,7 @@ function registerWebhookSubscriptionTools(server, callApi) {
|
|
|
4068
4430
|
}
|
|
4069
4431
|
|
|
4070
4432
|
// src/mcp/tools/domain-templates.ts
|
|
4071
|
-
import { z as
|
|
4433
|
+
import { z as z13 } from "zod";
|
|
4072
4434
|
function registerDomainTemplateTools(server, callApi) {
|
|
4073
4435
|
server.registerTool(
|
|
4074
4436
|
"lexq_domain_templates_list",
|
|
@@ -4085,7 +4447,7 @@ function registerDomainTemplateTools(server, callApi) {
|
|
|
4085
4447
|
title: "Preview Domain Template",
|
|
4086
4448
|
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.",
|
|
4087
4449
|
inputSchema: {
|
|
4088
|
-
template:
|
|
4450
|
+
template: z13.string().describe(
|
|
4089
4451
|
"Domain template key (e.g. ECOMMERCE). Use lexq_domain_templates_list to see available keys \u2014 currently only ECOMMERCE is ACTIVE."
|
|
4090
4452
|
)
|
|
4091
4453
|
}
|
|
@@ -4098,8 +4460,8 @@ function registerDomainTemplateTools(server, callApi) {
|
|
|
4098
4460
|
title: "Apply Domain Template",
|
|
4099
4461
|
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.",
|
|
4100
4462
|
inputSchema: {
|
|
4101
|
-
template:
|
|
4102
|
-
customName:
|
|
4463
|
+
template: z13.string().describe("Domain template key to apply (e.g. ECOMMERCE)."),
|
|
4464
|
+
customName: z13.string().optional().describe(
|
|
4103
4465
|
"Optional custom name for the policy group that gets created. If omitted, the template's default name is used."
|
|
4104
4466
|
)
|
|
4105
4467
|
}
|
|
@@ -4121,7 +4483,9 @@ function registerAllTools(server, callApi) {
|
|
|
4121
4483
|
registerFactTools(server, callApi);
|
|
4122
4484
|
registerDeployTools(server, callApi);
|
|
4123
4485
|
registerAnalyticsTools(server, callApi);
|
|
4486
|
+
registerReplayTools(server, callApi);
|
|
4124
4487
|
registerHistoryTools(server, callApi);
|
|
4488
|
+
registerProvenanceTools(server, callApi);
|
|
4125
4489
|
registerIntegrationTools(server, callApi);
|
|
4126
4490
|
registerLogTools(server, callApi);
|
|
4127
4491
|
registerDomainTemplateTools(server, callApi);
|
|
@@ -4153,12 +4517,12 @@ async function startMcpServer() {
|
|
|
4153
4517
|
function registerServeCommand(program) {
|
|
4154
4518
|
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(
|
|
4155
4519
|
"after",
|
|
4156
|
-
|
|
4520
|
+
dedent17`
|
|
4157
4521
|
|
|
4158
4522
|
Example:
|
|
4159
4523
|
$ lexq serve --mcp
|
|
4160
4524
|
|
|
4161
|
-
Starts a stdio MCP server that exposes
|
|
4525
|
+
Starts a stdio MCP server that exposes the full LexQ toolset for policy management.
|
|
4162
4526
|
Used by Claude Desktop, Claude.ai, Cursor, and other MCP-compatible clients.
|
|
4163
4527
|
|
|
4164
4528
|
Claude Desktop config (~/.claude/claude_desktop_config.json):
|
|
@@ -4184,11 +4548,11 @@ function registerServeCommand(program) {
|
|
|
4184
4548
|
|
|
4185
4549
|
// src/commands/domain-templates.ts
|
|
4186
4550
|
import "commander";
|
|
4187
|
-
import
|
|
4551
|
+
import dedent18 from "dedent";
|
|
4188
4552
|
function registerDomainTemplateCommands(program) {
|
|
4189
4553
|
const templates = program.command("domain-templates").description("Browse and apply domain templates").addHelpText(
|
|
4190
4554
|
"after",
|
|
4191
|
-
|
|
4555
|
+
dedent18`
|
|
4192
4556
|
|
|
4193
4557
|
A domain template is an industry-specific starter pack of fact
|
|
4194
4558
|
definitions and sample rules. Applying one provisions a ready-to-use
|
|
@@ -4236,7 +4600,7 @@ function registerDomainTemplateCommands(program) {
|
|
|
4236
4600
|
});
|
|
4237
4601
|
templates.command("preview").description("Preview what a domain template provisions").requiredOption("--template <key>", "Domain template key (e.g. ECOMMERCE)").addHelpText(
|
|
4238
4602
|
"after",
|
|
4239
|
-
|
|
4603
|
+
dedent18`
|
|
4240
4604
|
|
|
4241
4605
|
Read-only dry run — shows the fact definitions and sample rules the
|
|
4242
4606
|
template will create. Nothing is provisioned.
|
|
@@ -4265,7 +4629,7 @@ function registerDomainTemplateCommands(program) {
|
|
|
4265
4629
|
});
|
|
4266
4630
|
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(
|
|
4267
4631
|
"after",
|
|
4268
|
-
|
|
4632
|
+
dedent18`
|
|
4269
4633
|
|
|
4270
4634
|
Creates the template's fact definitions and a new DRAFT policy group
|
|
4271
4635
|
populated with its sample rules. Existing facts are skipped — apply is
|
|
@@ -4327,7 +4691,10 @@ function createCli() {
|
|
|
4327
4691
|
const program = new Command();
|
|
4328
4692
|
program.name("lexq").description(
|
|
4329
4693
|
"Command-line interface for the LexQ Decision Operations Platform. Manage policies, run Impact Simulation, and deploy from your terminal."
|
|
4330
|
-
).version(getVersion2(), "-V, --version").option("--format <format>", "Output format: json or table", "json").option("--api-key <key>", "Override stored API key").option(
|
|
4694
|
+
).version(getVersion2(), "-V, --version").option("--format <format>", "Output format: json or table", "json").option("--api-key <key>", "Override stored API key").option(
|
|
4695
|
+
"--base-url <url>",
|
|
4696
|
+
"Override API base URL \u2014 must include the API prefix, e.g. http://localhost:8080/api/v1/partners"
|
|
4697
|
+
).option("--dry-run", "Preview the HTTP request without executing").option("--verbose", "Show request/response details").option("--no-color", "Disable colored output");
|
|
4331
4698
|
registerAuthCommands(program);
|
|
4332
4699
|
registerStatusCommand(program);
|
|
4333
4700
|
registerGroupCommands(program);
|
|
@@ -4338,6 +4705,8 @@ function createCli() {
|
|
|
4338
4705
|
registerDeployCommands(program);
|
|
4339
4706
|
registerAnalyticsCommands(program);
|
|
4340
4707
|
registerHistoryCommands(program);
|
|
4708
|
+
registerReplayCommands(program);
|
|
4709
|
+
registerProvenanceCommands(program);
|
|
4341
4710
|
registerIntegrationCommands(program);
|
|
4342
4711
|
registerLogCommands(program);
|
|
4343
4712
|
registerWebhookSubscriptionCommands(program);
|