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