@lexq/cli 0.1.23 → 0.1.26
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/README.md +12 -35
- package/dist/index.js +178 -0
- package/dist/mcp/register.d.ts +1 -1
- package/dist/mcp/register.js +46 -0
- package/package.json +11 -9
package/README.md
CHANGED
|
@@ -53,48 +53,24 @@ lexq auth login
|
|
|
53
53
|
# 2. Verify
|
|
54
54
|
lexq auth whoami
|
|
55
55
|
|
|
56
|
-
# 3.
|
|
57
|
-
lexq
|
|
58
|
-
|
|
59
|
-
#
|
|
60
|
-
lexq versions create --group-id <GROUP_ID> --json '{"commitMessage":"v1"}'
|
|
61
|
-
|
|
62
|
-
# 5. Add a rule
|
|
63
|
-
lexq rules create --group-id <GROUP_ID> --version-id <VERSION_ID> --json '{
|
|
64
|
-
"name": "VIP Discount",
|
|
65
|
-
"priority": 0,
|
|
66
|
-
"condition": {
|
|
67
|
-
"type": "SINGLE",
|
|
68
|
-
"field": "customer_tier",
|
|
69
|
-
"operator": "EQUALS",
|
|
70
|
-
"value": "VIP",
|
|
71
|
-
"valueType": "STRING"
|
|
72
|
-
},
|
|
73
|
-
"actions": [{
|
|
74
|
-
"type": "MUTATE_FACT",
|
|
75
|
-
"parameters": {
|
|
76
|
-
"method": "PERCENTAGE",
|
|
77
|
-
"rate": 10,
|
|
78
|
-
"refVar": "payment_amount",
|
|
79
|
-
"operator": "SUB",
|
|
80
|
-
"rounding": { "mode": "HALF_UP", "scale": 0 }
|
|
81
|
-
}
|
|
82
|
-
}]
|
|
83
|
-
}'
|
|
56
|
+
# 3. Start from a domain template — provisions facts, sample rules, and a policy group
|
|
57
|
+
lexq domain-templates list
|
|
58
|
+
lexq domain-templates apply --template ECOMMERCE
|
|
59
|
+
# Returns: policyGroupId, policyVersionId, factsCreated, rulesCreated
|
|
84
60
|
|
|
85
|
-
#
|
|
61
|
+
# 4. Test a rule against your data before shipping
|
|
86
62
|
lexq analytics dry-run --version-id <VERSION_ID> --debug --mock \
|
|
87
|
-
--json '{"facts":{"
|
|
63
|
+
--json '{"facts":{"loyalty_tier":"PLATINUM","purchase_subtotal_usd":150}}'
|
|
88
64
|
|
|
89
|
-
#
|
|
65
|
+
# 5. Deploy
|
|
90
66
|
lexq deploy publish --group-id <GROUP_ID> --version-id <VERSION_ID> --memo "v1"
|
|
91
67
|
lexq deploy live --group-id <GROUP_ID> --version-id <VERSION_ID> --memo "Initial deploy"
|
|
92
68
|
```
|
|
93
69
|
|
|
94
|
-
## For AI Agents —
|
|
70
|
+
## For AI Agents — the Complete Partner API
|
|
95
71
|
|
|
96
|
-
LexQ is designed to be AI-native. The entire policy engine API
|
|
97
|
-
|
|
72
|
+
LexQ is designed to be AI-native. The entire policy engine Partner API is
|
|
73
|
+
exposed via Model Context Protocol. Claude, Cursor, and other MCP-compatible
|
|
98
74
|
agents can create, simulate, and deploy rules autonomously, with human approval
|
|
99
75
|
before production.
|
|
100
76
|
|
|
@@ -103,7 +79,7 @@ before production.
|
|
|
103
79
|
1. **Settings → Connectors → Add Custom Integration**
|
|
104
80
|
2. Enter: `https://mcp.lexq.io`
|
|
105
81
|
3. Sign in with your LexQ account and select an API key
|
|
106
|
-
4. Done —
|
|
82
|
+
4. Done — the full toolset available in every conversation
|
|
107
83
|
|
|
108
84
|
### Remote (Streamable HTTP)
|
|
109
85
|
|
|
@@ -210,6 +186,7 @@ lexq groups ab-test start | stop | adjust
|
|
|
210
186
|
lexq versions list | get | create | update | delete | clone
|
|
211
187
|
lexq rules list | get | create | update | delete | reorder | toggle
|
|
212
188
|
lexq facts list | create | update | delete | action-metadata
|
|
189
|
+
lexq domain-templates list | preview | apply
|
|
213
190
|
lexq deploy publish | live | rollback | undeploy | history | detail | overview | deployable | diff
|
|
214
191
|
lexq analytics dry-run | dry-run-compare | requirements
|
|
215
192
|
lexq analytics simulation start | status | list | cancel | export
|
package/dist/index.js
CHANGED
|
@@ -3910,6 +3910,51 @@ function registerWebhookSubscriptionTools(server, callApi) {
|
|
|
3910
3910
|
);
|
|
3911
3911
|
}
|
|
3912
3912
|
|
|
3913
|
+
// src/mcp/tools/domain-templates.ts
|
|
3914
|
+
import { z as z11 } from "zod";
|
|
3915
|
+
function registerDomainTemplateTools(server, callApi) {
|
|
3916
|
+
server.registerTool(
|
|
3917
|
+
"lexq_domain_templates_list",
|
|
3918
|
+
{
|
|
3919
|
+
title: "List Domain Templates",
|
|
3920
|
+
description: "List all domain templates. A domain template is a curated, industry-specific starter pack of fact definitions and sample rules (e.g. ECOMMERCE). Each entry reports its key, status (ACTIVE or COMING_SOON), and a summary of what it provisions. Call this before preview or apply to discover which templates can currently be applied.",
|
|
3921
|
+
inputSchema: {}
|
|
3922
|
+
},
|
|
3923
|
+
async () => callApi("GET", "domain-templates")
|
|
3924
|
+
);
|
|
3925
|
+
server.registerTool(
|
|
3926
|
+
"lexq_domain_templates_preview",
|
|
3927
|
+
{
|
|
3928
|
+
title: "Preview Domain Template",
|
|
3929
|
+
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.",
|
|
3930
|
+
inputSchema: {
|
|
3931
|
+
template: z11.string().describe(
|
|
3932
|
+
"Domain template key (e.g. ECOMMERCE). Use lexq_domain_templates_list to see available keys \u2014 currently only ECOMMERCE is ACTIVE."
|
|
3933
|
+
)
|
|
3934
|
+
}
|
|
3935
|
+
},
|
|
3936
|
+
async ({ template }) => callApi("GET", `domain-templates/${template}/preview`)
|
|
3937
|
+
);
|
|
3938
|
+
server.registerTool(
|
|
3939
|
+
"lexq_domain_templates_apply",
|
|
3940
|
+
{
|
|
3941
|
+
title: "Apply Domain Template",
|
|
3942
|
+
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.",
|
|
3943
|
+
inputSchema: {
|
|
3944
|
+
template: z11.string().describe("Domain template key to apply (e.g. ECOMMERCE)."),
|
|
3945
|
+
customName: z11.string().optional().describe(
|
|
3946
|
+
"Optional custom name for the policy group that gets created. If omitted, the template's default name is used."
|
|
3947
|
+
)
|
|
3948
|
+
}
|
|
3949
|
+
},
|
|
3950
|
+
async ({ template, customName }) => {
|
|
3951
|
+
const body = {};
|
|
3952
|
+
if (customName !== void 0) body.customName = customName;
|
|
3953
|
+
return callApi("POST", `domain-templates/${template}/apply`, { body });
|
|
3954
|
+
}
|
|
3955
|
+
);
|
|
3956
|
+
}
|
|
3957
|
+
|
|
3913
3958
|
// src/mcp/register.ts
|
|
3914
3959
|
function registerAllTools(server, callApi) {
|
|
3915
3960
|
registerStatusTools(server, callApi);
|
|
@@ -3922,6 +3967,7 @@ function registerAllTools(server, callApi) {
|
|
|
3922
3967
|
registerHistoryTools(server, callApi);
|
|
3923
3968
|
registerIntegrationTools(server, callApi);
|
|
3924
3969
|
registerLogTools(server, callApi);
|
|
3970
|
+
registerDomainTemplateTools(server, callApi);
|
|
3925
3971
|
registerWebhookSubscriptionTools(server, callApi);
|
|
3926
3972
|
}
|
|
3927
3973
|
|
|
@@ -3979,6 +4025,137 @@ function registerServeCommand(program) {
|
|
|
3979
4025
|
});
|
|
3980
4026
|
}
|
|
3981
4027
|
|
|
4028
|
+
// src/commands/domain-templates.ts
|
|
4029
|
+
import "commander";
|
|
4030
|
+
import dedent16 from "dedent";
|
|
4031
|
+
function registerDomainTemplateCommands(program) {
|
|
4032
|
+
const templates = program.command("domain-templates").description("Browse and apply domain templates").addHelpText(
|
|
4033
|
+
"after",
|
|
4034
|
+
dedent16`
|
|
4035
|
+
|
|
4036
|
+
A domain template is an industry-specific starter pack of fact
|
|
4037
|
+
definitions and sample rules. Applying one provisions a ready-to-use
|
|
4038
|
+
policy group so you start from a working baseline instead of an
|
|
4039
|
+
empty schema.
|
|
4040
|
+
|
|
4041
|
+
Commands:
|
|
4042
|
+
list List available domain templates
|
|
4043
|
+
preview Preview the facts and rules a template provisions
|
|
4044
|
+
apply Apply a template to the current tenant
|
|
4045
|
+
|
|
4046
|
+
Workflow: list → preview → apply
|
|
4047
|
+
Currently available: ECOMMERCE (FINTECH, SAAS — coming soon)
|
|
4048
|
+
`
|
|
4049
|
+
);
|
|
4050
|
+
templates.command("list").description("List available domain templates").action(async () => {
|
|
4051
|
+
try {
|
|
4052
|
+
const globalOpts = program.opts();
|
|
4053
|
+
const format = globalOpts.format ?? "json";
|
|
4054
|
+
const data = await apiRequest("GET", "domain-templates", {
|
|
4055
|
+
apiKey: globalOpts.apiKey,
|
|
4056
|
+
baseUrl: globalOpts.baseUrl,
|
|
4057
|
+
dryRun: globalOpts.dryRun,
|
|
4058
|
+
verbose: globalOpts.verbose
|
|
4059
|
+
});
|
|
4060
|
+
if (format === "table") {
|
|
4061
|
+
printTable(
|
|
4062
|
+
["Template", "Name", "Facts", "Rules", "Available"],
|
|
4063
|
+
data.map((t) => [
|
|
4064
|
+
t.template,
|
|
4065
|
+
t.displayName,
|
|
4066
|
+
String(t.factCount),
|
|
4067
|
+
String(t.ruleCount),
|
|
4068
|
+
t.isAvailable ? "\u2713" : "\u2013"
|
|
4069
|
+
]),
|
|
4070
|
+
{ truncate: 32 }
|
|
4071
|
+
);
|
|
4072
|
+
} else {
|
|
4073
|
+
printJson(data);
|
|
4074
|
+
}
|
|
4075
|
+
} catch (error) {
|
|
4076
|
+
printError(error);
|
|
4077
|
+
process.exit(1);
|
|
4078
|
+
}
|
|
4079
|
+
});
|
|
4080
|
+
templates.command("preview").description("Preview what a domain template provisions").requiredOption("--template <key>", "Domain template key (e.g. ECOMMERCE)").addHelpText(
|
|
4081
|
+
"after",
|
|
4082
|
+
dedent16`
|
|
4083
|
+
|
|
4084
|
+
Read-only dry run — shows the fact definitions and sample rules the
|
|
4085
|
+
template will create. Nothing is provisioned.
|
|
4086
|
+
|
|
4087
|
+
Example:
|
|
4088
|
+
$ lexq domain-templates preview --template ECOMMERCE
|
|
4089
|
+
`
|
|
4090
|
+
).action(async (opts) => {
|
|
4091
|
+
try {
|
|
4092
|
+
const globalOpts = program.opts();
|
|
4093
|
+
const data = await apiRequest(
|
|
4094
|
+
"GET",
|
|
4095
|
+
`domain-templates/${opts.template}/preview`,
|
|
4096
|
+
{
|
|
4097
|
+
apiKey: globalOpts.apiKey,
|
|
4098
|
+
baseUrl: globalOpts.baseUrl,
|
|
4099
|
+
dryRun: globalOpts.dryRun,
|
|
4100
|
+
verbose: globalOpts.verbose
|
|
4101
|
+
}
|
|
4102
|
+
);
|
|
4103
|
+
printJson(data);
|
|
4104
|
+
} catch (error) {
|
|
4105
|
+
printError(error);
|
|
4106
|
+
process.exit(1);
|
|
4107
|
+
}
|
|
4108
|
+
});
|
|
4109
|
+
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(
|
|
4110
|
+
"after",
|
|
4111
|
+
dedent16`
|
|
4112
|
+
|
|
4113
|
+
Creates the template's fact definitions and a new DRAFT policy group
|
|
4114
|
+
populated with its sample rules. Existing facts are skipped — apply is
|
|
4115
|
+
additive and never overwrites your schema.
|
|
4116
|
+
|
|
4117
|
+
Run "preview" first to review what will be created.
|
|
4118
|
+
|
|
4119
|
+
Example:
|
|
4120
|
+
$ lexq domain-templates apply --template ECOMMERCE
|
|
4121
|
+
$ lexq domain-templates apply --template ECOMMERCE --name "My Store Policy"
|
|
4122
|
+
`
|
|
4123
|
+
).action(async (opts) => {
|
|
4124
|
+
try {
|
|
4125
|
+
const globalOpts = program.opts();
|
|
4126
|
+
if (!opts.force) {
|
|
4127
|
+
const { createInterface: createInterface2 } = await import("readline/promises");
|
|
4128
|
+
const rl = createInterface2({ input: process.stdin, output: process.stdout });
|
|
4129
|
+
const answer = await rl.question(
|
|
4130
|
+
`Apply domain template ${opts.template} to the current tenant? [y/N] `
|
|
4131
|
+
);
|
|
4132
|
+
rl.close();
|
|
4133
|
+
if (answer.toLowerCase() !== "y") {
|
|
4134
|
+
console.log("Cancelled.");
|
|
4135
|
+
return;
|
|
4136
|
+
}
|
|
4137
|
+
}
|
|
4138
|
+
const body = {};
|
|
4139
|
+
if (opts.name) body.customName = opts.name;
|
|
4140
|
+
const data = await apiRequest(
|
|
4141
|
+
"POST",
|
|
4142
|
+
`domain-templates/${opts.template}/apply`,
|
|
4143
|
+
{
|
|
4144
|
+
apiKey: globalOpts.apiKey,
|
|
4145
|
+
baseUrl: globalOpts.baseUrl,
|
|
4146
|
+
dryRun: globalOpts.dryRun,
|
|
4147
|
+
verbose: globalOpts.verbose,
|
|
4148
|
+
body
|
|
4149
|
+
}
|
|
4150
|
+
);
|
|
4151
|
+
printJson(data);
|
|
4152
|
+
} catch (error) {
|
|
4153
|
+
printError(error);
|
|
4154
|
+
process.exit(1);
|
|
4155
|
+
}
|
|
4156
|
+
});
|
|
4157
|
+
}
|
|
4158
|
+
|
|
3982
4159
|
// src/cli.ts
|
|
3983
4160
|
var __dirname2 = dirname2(fileURLToPath2(import.meta.url));
|
|
3984
4161
|
function getVersion2() {
|
|
@@ -4000,6 +4177,7 @@ function createCli() {
|
|
|
4000
4177
|
registerVersionCommands(program);
|
|
4001
4178
|
registerRuleCommands(program);
|
|
4002
4179
|
registerFactCommands(program);
|
|
4180
|
+
registerDomainTemplateCommands(program);
|
|
4003
4181
|
registerDeployCommands(program);
|
|
4004
4182
|
registerAnalyticsCommands(program);
|
|
4005
4183
|
registerHistoryCommands(program);
|
package/dist/mcp/register.d.ts
CHANGED
|
@@ -27,7 +27,7 @@ type CallApi = (method: string, path: string, opts?: {
|
|
|
27
27
|
declare function paginationParams(page?: number, size?: number): Record<string, string>;
|
|
28
28
|
|
|
29
29
|
/**
|
|
30
|
-
* Registers all
|
|
30
|
+
* Registers all 66 MCP tools on the given server.
|
|
31
31
|
*
|
|
32
32
|
* @param server - McpServer instance
|
|
33
33
|
* @param callApi - API caller function (config-based for CLI, Bearer-based for HTTP)
|
package/dist/mcp/register.js
CHANGED
|
@@ -1109,6 +1109,51 @@ function registerWebhookSubscriptionTools(server, callApi) {
|
|
|
1109
1109
|
);
|
|
1110
1110
|
}
|
|
1111
1111
|
|
|
1112
|
+
// src/mcp/tools/domain-templates.ts
|
|
1113
|
+
import { z as z11 } from "zod";
|
|
1114
|
+
function registerDomainTemplateTools(server, callApi) {
|
|
1115
|
+
server.registerTool(
|
|
1116
|
+
"lexq_domain_templates_list",
|
|
1117
|
+
{
|
|
1118
|
+
title: "List Domain Templates",
|
|
1119
|
+
description: "List all domain templates. A domain template is a curated, industry-specific starter pack of fact definitions and sample rules (e.g. ECOMMERCE). Each entry reports its key, status (ACTIVE or COMING_SOON), and a summary of what it provisions. Call this before preview or apply to discover which templates can currently be applied.",
|
|
1120
|
+
inputSchema: {}
|
|
1121
|
+
},
|
|
1122
|
+
async () => callApi("GET", "domain-templates")
|
|
1123
|
+
);
|
|
1124
|
+
server.registerTool(
|
|
1125
|
+
"lexq_domain_templates_preview",
|
|
1126
|
+
{
|
|
1127
|
+
title: "Preview Domain Template",
|
|
1128
|
+
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.",
|
|
1129
|
+
inputSchema: {
|
|
1130
|
+
template: z11.string().describe(
|
|
1131
|
+
"Domain template key (e.g. ECOMMERCE). Use lexq_domain_templates_list to see available keys \u2014 currently only ECOMMERCE is ACTIVE."
|
|
1132
|
+
)
|
|
1133
|
+
}
|
|
1134
|
+
},
|
|
1135
|
+
async ({ template }) => callApi("GET", `domain-templates/${template}/preview`)
|
|
1136
|
+
);
|
|
1137
|
+
server.registerTool(
|
|
1138
|
+
"lexq_domain_templates_apply",
|
|
1139
|
+
{
|
|
1140
|
+
title: "Apply Domain Template",
|
|
1141
|
+
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.",
|
|
1142
|
+
inputSchema: {
|
|
1143
|
+
template: z11.string().describe("Domain template key to apply (e.g. ECOMMERCE)."),
|
|
1144
|
+
customName: z11.string().optional().describe(
|
|
1145
|
+
"Optional custom name for the policy group that gets created. If omitted, the template's default name is used."
|
|
1146
|
+
)
|
|
1147
|
+
}
|
|
1148
|
+
},
|
|
1149
|
+
async ({ template, customName }) => {
|
|
1150
|
+
const body = {};
|
|
1151
|
+
if (customName !== void 0) body.customName = customName;
|
|
1152
|
+
return callApi("POST", `domain-templates/${template}/apply`, { body });
|
|
1153
|
+
}
|
|
1154
|
+
);
|
|
1155
|
+
}
|
|
1156
|
+
|
|
1112
1157
|
// src/mcp/register.ts
|
|
1113
1158
|
function registerAllTools(server, callApi) {
|
|
1114
1159
|
registerStatusTools(server, callApi);
|
|
@@ -1121,6 +1166,7 @@ function registerAllTools(server, callApi) {
|
|
|
1121
1166
|
registerHistoryTools(server, callApi);
|
|
1122
1167
|
registerIntegrationTools(server, callApi);
|
|
1123
1168
|
registerLogTools(server, callApi);
|
|
1169
|
+
registerDomainTemplateTools(server, callApi);
|
|
1124
1170
|
registerWebhookSubscriptionTools(server, callApi);
|
|
1125
1171
|
}
|
|
1126
1172
|
export {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lexq/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.26",
|
|
4
4
|
"description": "LexQ CLI — manage policies, simulate rules, and deploy from the terminal. Built for humans and AI agents.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -23,6 +23,14 @@
|
|
|
23
23
|
"publishConfig": {
|
|
24
24
|
"access": "public"
|
|
25
25
|
},
|
|
26
|
+
"scripts": {
|
|
27
|
+
"dev": "tsup --watch",
|
|
28
|
+
"build": "tsup",
|
|
29
|
+
"lint": "eslint src/",
|
|
30
|
+
"typecheck": "tsc --noEmit",
|
|
31
|
+
"start": "node dist/index.js",
|
|
32
|
+
"prepublishOnly": "pnpm build"
|
|
33
|
+
},
|
|
26
34
|
"keywords": [
|
|
27
35
|
"lexq",
|
|
28
36
|
"rule-engine",
|
|
@@ -43,6 +51,7 @@
|
|
|
43
51
|
"engines": {
|
|
44
52
|
"node": ">=18.0.0"
|
|
45
53
|
},
|
|
54
|
+
"packageManager": "pnpm@10.28.0",
|
|
46
55
|
"dependencies": {
|
|
47
56
|
"@modelcontextprotocol/sdk": "^1.28.0",
|
|
48
57
|
"cli-table3": "^0.6.5",
|
|
@@ -60,12 +69,5 @@
|
|
|
60
69
|
"tsup": "^8.5.1",
|
|
61
70
|
"typescript": "^5.7.0",
|
|
62
71
|
"typescript-eslint": "^8.24.0"
|
|
63
|
-
},
|
|
64
|
-
"scripts": {
|
|
65
|
-
"dev": "tsup --watch",
|
|
66
|
-
"build": "tsup",
|
|
67
|
-
"lint": "eslint src/",
|
|
68
|
-
"typecheck": "tsc --noEmit",
|
|
69
|
-
"start": "node dist/index.js"
|
|
70
72
|
}
|
|
71
|
-
}
|
|
73
|
+
}
|