@lexq/cli 0.1.6 → 0.1.8
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 +2 -1
- package/README.md +2 -1
- package/dist/index.js +189 -46
- package/dist/index.js.map +1 -1
- package/dist/mcp/register.d.ts +37 -0
- package/dist/mcp/register.js +1001 -0
- package/dist/mcp/register.js.map +1 -0
- package/package.json +8 -1
- package/skills/lexq-simulation/SKILL.md +22 -0
package/AGENTS.md
CHANGED
|
@@ -46,7 +46,7 @@ Detailed documentation lives in the `skills/` directory. **Read the relevant ski
|
|
|
46
46
|
6. **Copy full UUIDs from output.** Never guess or truncate IDs.
|
|
47
47
|
7. **Handle errors gracefully.** Check the error code and follow the action table in `lexq-shared/SKILL.md`.
|
|
48
48
|
|
|
49
|
-
## Complete Command Inventory (
|
|
49
|
+
## Complete Command Inventory (63 commands)
|
|
50
50
|
|
|
51
51
|
```
|
|
52
52
|
lexq auth login|logout|whoami
|
|
@@ -59,6 +59,7 @@ lexq facts list|create|update|delete
|
|
|
59
59
|
lexq deploy publish|live|rollback|undeploy|history|detail|overview
|
|
60
60
|
lexq analytics dry-run|dry-run-compare|requirements
|
|
61
61
|
lexq analytics simulation start|status|list|cancel|export
|
|
62
|
+
lexq analytics dataset upload|template
|
|
62
63
|
lexq history list|get|stats
|
|
63
64
|
lexq integrations list|get|save|delete|config-spec
|
|
64
65
|
lexq logs list|get|action|bulk-action
|
package/README.md
CHANGED
|
@@ -74,6 +74,7 @@ lexq facts list | create | update | delete
|
|
|
74
74
|
lexq deploy publish | live | rollback | undeploy | history | detail | overview
|
|
75
75
|
lexq analytics dry-run | dry-run-compare | requirements
|
|
76
76
|
lexq analytics simulation start | status | list | cancel | export
|
|
77
|
+
lexq analytics dataset upload | template
|
|
77
78
|
lexq history list | get | stats
|
|
78
79
|
lexq integrations list | get | save | delete | config-spec
|
|
79
80
|
lexq logs list | get | action | bulk-action
|
|
@@ -156,7 +157,7 @@ Run LexQ CLI as an MCP (Model Context Protocol) server for seamless AI agent int
|
|
|
156
157
|
lexq serve --mcp
|
|
157
158
|
```
|
|
158
159
|
|
|
159
|
-
This starts a stdio MCP server exposing
|
|
160
|
+
This starts a stdio MCP server exposing 55 tools — the full LexQ API — to any MCP-compatible client.
|
|
160
161
|
|
|
161
162
|
### Claude Desktop
|
|
162
163
|
|
package/dist/index.js
CHANGED
|
@@ -1200,7 +1200,7 @@ ${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
|
|
|
1200
1200
|
}
|
|
1201
1201
|
|
|
1202
1202
|
// src/commands/analytics.ts
|
|
1203
|
-
import { readFileSync as readFileSync2 } from "fs";
|
|
1203
|
+
import { readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
1204
1204
|
import "commander";
|
|
1205
1205
|
function registerAnalyticsCommands(program) {
|
|
1206
1206
|
const analytics = program.command("analytics").description("Dry run, simulation, and requirements");
|
|
@@ -1464,7 +1464,6 @@ ${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
|
|
|
1464
1464
|
}
|
|
1465
1465
|
);
|
|
1466
1466
|
if (opts.output) {
|
|
1467
|
-
const { writeFileSync: writeFileSync2 } = await import("fs");
|
|
1468
1467
|
const text = typeof response === "string" ? response : JSON.stringify(response, null, 2);
|
|
1469
1468
|
writeFileSync2(opts.output, text, "utf-8");
|
|
1470
1469
|
console.log(`\u2713 Exported to ${opts.output}`);
|
|
@@ -1476,6 +1475,83 @@ ${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
|
|
|
1476
1475
|
process.exit(1);
|
|
1477
1476
|
}
|
|
1478
1477
|
});
|
|
1478
|
+
const dataset = analytics.command("dataset").description("Upload datasets and download templates");
|
|
1479
|
+
dataset.command("upload").description("Upload a CSV or JSON file as a simulation dataset").requiredOption("--file <path>", "Path to CSV or JSON file").action(async (opts) => {
|
|
1480
|
+
try {
|
|
1481
|
+
const globalOpts = program.opts();
|
|
1482
|
+
const config = loadConfig();
|
|
1483
|
+
const baseUrl = globalOpts.baseUrl ?? config.baseUrl;
|
|
1484
|
+
const apiKey = globalOpts.apiKey ?? config.apiKey;
|
|
1485
|
+
if (!apiKey) {
|
|
1486
|
+
throw new Error('Not authenticated. Run "lexq auth login" first.');
|
|
1487
|
+
}
|
|
1488
|
+
const filePath = opts.file;
|
|
1489
|
+
const fileBuffer = readFileSync2(filePath);
|
|
1490
|
+
const fileName = filePath.split("/").pop() ?? "dataset";
|
|
1491
|
+
const ext = fileName.split(".").pop()?.toLowerCase();
|
|
1492
|
+
let contentType = "application/octet-stream";
|
|
1493
|
+
if (ext === "csv") contentType = "text/csv";
|
|
1494
|
+
else if (ext === "json") contentType = "application/json";
|
|
1495
|
+
const blob = new Blob([fileBuffer], { type: contentType });
|
|
1496
|
+
const formData = new FormData();
|
|
1497
|
+
formData.append("file", blob, fileName);
|
|
1498
|
+
const url = new URL("analytics/datasets/upload", baseUrl.endsWith("/") ? baseUrl : baseUrl + "/");
|
|
1499
|
+
if (globalOpts.verbose) {
|
|
1500
|
+
console.error(`\u2192 POST ${url.toString()}`);
|
|
1501
|
+
console.error(` File: ${filePath} (${fileBuffer.length} bytes)`);
|
|
1502
|
+
}
|
|
1503
|
+
const response = await fetch(url.toString(), {
|
|
1504
|
+
method: "POST",
|
|
1505
|
+
headers: { "X-API-KEY": apiKey },
|
|
1506
|
+
body: formData
|
|
1507
|
+
});
|
|
1508
|
+
if (!response.ok) {
|
|
1509
|
+
const errorText = await response.text();
|
|
1510
|
+
throw new Error(`Upload failed (${response.status}): ${errorText}`);
|
|
1511
|
+
}
|
|
1512
|
+
const envelope = await response.json();
|
|
1513
|
+
const result = envelope.data;
|
|
1514
|
+
console.log(`\u2713 Dataset uploaded: ${result.path}`);
|
|
1515
|
+
console.log(` File: ${result.filename} (${result.size} bytes)`);
|
|
1516
|
+
printJson(result);
|
|
1517
|
+
} catch (error) {
|
|
1518
|
+
printError(error);
|
|
1519
|
+
process.exit(1);
|
|
1520
|
+
}
|
|
1521
|
+
});
|
|
1522
|
+
dataset.command("template").description("Download a dataset template based on version requirements").requiredOption("--group-id <groupId>", "Policy group ID").requiredOption("--version-id <versionId>", "Policy version ID").option("--format <fmt>", "Template format: csv or json", "csv").option("--output <path>", "Output file path").action(async (opts) => {
|
|
1523
|
+
try {
|
|
1524
|
+
const globalOpts = program.opts();
|
|
1525
|
+
const config = loadConfig();
|
|
1526
|
+
const baseUrl = globalOpts.baseUrl ?? config.baseUrl;
|
|
1527
|
+
const apiKey = globalOpts.apiKey ?? config.apiKey;
|
|
1528
|
+
if (!apiKey) {
|
|
1529
|
+
throw new Error('Not authenticated. Run "lexq auth login" first.');
|
|
1530
|
+
}
|
|
1531
|
+
const fmt = opts.format === "json" ? "json" : "csv";
|
|
1532
|
+
const url = new URL(
|
|
1533
|
+
`analytics/groups/${opts.groupId}/versions/${opts.versionId}/dataset-template`,
|
|
1534
|
+
baseUrl.endsWith("/") ? baseUrl : baseUrl + "/"
|
|
1535
|
+
);
|
|
1536
|
+
url.searchParams.set("format", fmt);
|
|
1537
|
+
const response = await fetch(url.toString(), {
|
|
1538
|
+
headers: { "X-API-KEY": apiKey, Accept: "*/*" }
|
|
1539
|
+
});
|
|
1540
|
+
if (!response.ok) {
|
|
1541
|
+
throw new Error(`Template download failed (${response.status})`);
|
|
1542
|
+
}
|
|
1543
|
+
const text = await response.text();
|
|
1544
|
+
if (opts.output) {
|
|
1545
|
+
writeFileSync2(opts.output, text, "utf-8");
|
|
1546
|
+
console.log(`\u2713 Template saved to ${opts.output}`);
|
|
1547
|
+
} else {
|
|
1548
|
+
console.log(text);
|
|
1549
|
+
}
|
|
1550
|
+
} catch (error) {
|
|
1551
|
+
printError(error);
|
|
1552
|
+
process.exit(1);
|
|
1553
|
+
}
|
|
1554
|
+
});
|
|
1479
1555
|
}
|
|
1480
1556
|
function resolveBody(opts) {
|
|
1481
1557
|
if (opts.file) {
|
|
@@ -1885,32 +1961,52 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
|
1885
1961
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
1886
1962
|
|
|
1887
1963
|
// src/mcp/tools/_shared.ts
|
|
1888
|
-
function
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1964
|
+
function createCallApiFromConfig() {
|
|
1965
|
+
return async (method, path, opts) => {
|
|
1966
|
+
try {
|
|
1967
|
+
const config = loadConfig();
|
|
1968
|
+
if (opts?.upload) {
|
|
1969
|
+
const url = new URL(path, config.baseUrl.endsWith("/") ? config.baseUrl : config.baseUrl + "/");
|
|
1970
|
+
if (opts.params) {
|
|
1971
|
+
for (const [key, value] of Object.entries(opts.params)) {
|
|
1972
|
+
if (value !== void 0) url.searchParams.set(key, value);
|
|
1973
|
+
}
|
|
1974
|
+
}
|
|
1975
|
+
if (!config.apiKey) {
|
|
1976
|
+
throw new Error('Not authenticated. Run "lexq auth login" first.');
|
|
1977
|
+
}
|
|
1978
|
+
const blob = new Blob([opts.upload.content], { type: "text/plain" });
|
|
1979
|
+
const formData = new FormData();
|
|
1980
|
+
formData.append(opts.upload.fieldName, blob, opts.upload.filename);
|
|
1981
|
+
const response = await fetch(url.toString(), {
|
|
1982
|
+
method,
|
|
1983
|
+
headers: { "X-API-KEY": config.apiKey },
|
|
1984
|
+
body: formData
|
|
1985
|
+
});
|
|
1986
|
+
const data2 = await response.json();
|
|
1987
|
+
return { content: [{ type: "text", text: JSON.stringify(data2, null, 2) }] };
|
|
1988
|
+
}
|
|
1989
|
+
const clientOpts = {
|
|
1990
|
+
apiKey: config.apiKey,
|
|
1991
|
+
baseUrl: config.baseUrl
|
|
1992
|
+
};
|
|
1993
|
+
const data = await apiRequest(method, path, {
|
|
1994
|
+
...clientOpts,
|
|
1995
|
+
body: opts?.body,
|
|
1996
|
+
params: opts?.params
|
|
1997
|
+
});
|
|
1998
|
+
return {
|
|
1999
|
+
content: [{ type: "text", text: JSON.stringify(data, null, 2) }]
|
|
2000
|
+
};
|
|
2001
|
+
} catch (error) {
|
|
2002
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2003
|
+
return {
|
|
2004
|
+
content: [{ type: "text", text: JSON.stringify({ error: message }) }],
|
|
2005
|
+
isError: true
|
|
2006
|
+
};
|
|
2007
|
+
}
|
|
1893
2008
|
};
|
|
1894
2009
|
}
|
|
1895
|
-
async function callApi(method, path, opts) {
|
|
1896
|
-
try {
|
|
1897
|
-
const clientOpts = getMcpClientOptions();
|
|
1898
|
-
const data = await apiRequest(method, path, {
|
|
1899
|
-
...clientOpts,
|
|
1900
|
-
body: opts?.body,
|
|
1901
|
-
params: opts?.params
|
|
1902
|
-
});
|
|
1903
|
-
return {
|
|
1904
|
-
content: [{ type: "text", text: JSON.stringify(data, null, 2) }]
|
|
1905
|
-
};
|
|
1906
|
-
} catch (error) {
|
|
1907
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
1908
|
-
return {
|
|
1909
|
-
content: [{ type: "text", text: JSON.stringify({ error: message }) }],
|
|
1910
|
-
isError: true
|
|
1911
|
-
};
|
|
1912
|
-
}
|
|
1913
|
-
}
|
|
1914
2010
|
function paginationParams(page, size) {
|
|
1915
2011
|
const params = {};
|
|
1916
2012
|
if (page !== void 0) params.page = String(page);
|
|
@@ -1919,7 +2015,7 @@ function paginationParams(page, size) {
|
|
|
1919
2015
|
}
|
|
1920
2016
|
|
|
1921
2017
|
// src/mcp/tools/status.ts
|
|
1922
|
-
function registerStatusTools(server) {
|
|
2018
|
+
function registerStatusTools(server, callApi) {
|
|
1923
2019
|
server.registerTool(
|
|
1924
2020
|
"lexq_whoami",
|
|
1925
2021
|
{
|
|
@@ -1933,7 +2029,7 @@ function registerStatusTools(server) {
|
|
|
1933
2029
|
|
|
1934
2030
|
// src/mcp/tools/groups.ts
|
|
1935
2031
|
import { z } from "zod";
|
|
1936
|
-
function registerGroupTools(server) {
|
|
2032
|
+
function registerGroupTools(server, callApi) {
|
|
1937
2033
|
server.registerTool(
|
|
1938
2034
|
"lexq_groups_list",
|
|
1939
2035
|
{
|
|
@@ -2068,7 +2164,7 @@ function registerGroupTools(server) {
|
|
|
2068
2164
|
|
|
2069
2165
|
// src/mcp/tools/versions.ts
|
|
2070
2166
|
import { z as z2 } from "zod";
|
|
2071
|
-
function registerVersionTools(server) {
|
|
2167
|
+
function registerVersionTools(server, callApi) {
|
|
2072
2168
|
server.registerTool(
|
|
2073
2169
|
"lexq_versions_list",
|
|
2074
2170
|
{
|
|
@@ -2160,7 +2256,7 @@ function registerVersionTools(server) {
|
|
|
2160
2256
|
|
|
2161
2257
|
// src/mcp/tools/rules.ts
|
|
2162
2258
|
import { z as z3 } from "zod";
|
|
2163
|
-
function registerRuleTools(server) {
|
|
2259
|
+
function registerRuleTools(server, callApi) {
|
|
2164
2260
|
server.registerTool(
|
|
2165
2261
|
"lexq_rules_list",
|
|
2166
2262
|
{
|
|
@@ -2312,7 +2408,7 @@ Types: DISCOUNT, POINT, COUPON_ISSUE, BLOCK, NOTIFICATION, WEBHOOK, SET_FACT, AD
|
|
|
2312
2408
|
|
|
2313
2409
|
// src/mcp/tools/facts.ts
|
|
2314
2410
|
import { z as z4 } from "zod";
|
|
2315
|
-
function registerFactTools(server) {
|
|
2411
|
+
function registerFactTools(server, callApi) {
|
|
2316
2412
|
server.registerTool(
|
|
2317
2413
|
"lexq_facts_list",
|
|
2318
2414
|
{
|
|
@@ -2374,7 +2470,7 @@ function registerFactTools(server) {
|
|
|
2374
2470
|
|
|
2375
2471
|
// src/mcp/tools/deploy.ts
|
|
2376
2472
|
import { z as z5 } from "zod";
|
|
2377
|
-
function registerDeployTools(server) {
|
|
2473
|
+
function registerDeployTools(server, callApi) {
|
|
2378
2474
|
server.registerTool(
|
|
2379
2475
|
"lexq_deploy_publish",
|
|
2380
2476
|
{
|
|
@@ -2478,7 +2574,7 @@ function registerDeployTools(server) {
|
|
|
2478
2574
|
|
|
2479
2575
|
// src/mcp/tools/analytics.ts
|
|
2480
2576
|
import { z as z6 } from "zod";
|
|
2481
|
-
function registerAnalyticsTools(server) {
|
|
2577
|
+
function registerAnalyticsTools(server, callApi) {
|
|
2482
2578
|
server.registerTool(
|
|
2483
2579
|
"lexq_dry_run",
|
|
2484
2580
|
{
|
|
@@ -2613,11 +2709,52 @@ Example body:
|
|
|
2613
2709
|
params: { format }
|
|
2614
2710
|
})
|
|
2615
2711
|
);
|
|
2712
|
+
server.registerTool(
|
|
2713
|
+
"lexq_dataset_upload",
|
|
2714
|
+
{
|
|
2715
|
+
title: "Upload Dataset",
|
|
2716
|
+
description: `Upload inline CSV or JSON content as a simulation dataset.
|
|
2717
|
+
The content is uploaded to S3 and a path is returned.
|
|
2718
|
+
Use this path in simulation start with dataset type UPLOADED.
|
|
2719
|
+
|
|
2720
|
+
CSV example:
|
|
2721
|
+
user_id,payment_amount
|
|
2722
|
+
user_001,150000
|
|
2723
|
+
user_002,50000
|
|
2724
|
+
|
|
2725
|
+
JSON example:
|
|
2726
|
+
[{"user_id":"user_001","payment_amount":150000}, {"user_id":"user_002","payment_amount":50000}]`,
|
|
2727
|
+
inputSchema: {
|
|
2728
|
+
content: z6.string().describe("CSV or JSON content as string"),
|
|
2729
|
+
filename: z6.string().default("dataset.csv").describe("Filename with extension (.csv or .json)")
|
|
2730
|
+
}
|
|
2731
|
+
},
|
|
2732
|
+
async ({ content, filename }) => callApi("POST", "analytics/datasets/upload", {
|
|
2733
|
+
upload: { content, filename, fieldName: "file" }
|
|
2734
|
+
})
|
|
2735
|
+
);
|
|
2736
|
+
server.registerTool(
|
|
2737
|
+
"lexq_dataset_template",
|
|
2738
|
+
{
|
|
2739
|
+
title: "Download Dataset Template",
|
|
2740
|
+
description: "Generate a sample CSV or JSON template based on the required facts of a version. Use this to understand the expected data format before uploading a dataset.",
|
|
2741
|
+
inputSchema: {
|
|
2742
|
+
groupId: z6.string().uuid().describe("Policy group ID"),
|
|
2743
|
+
versionId: z6.string().uuid().describe("Version ID"),
|
|
2744
|
+
format: z6.enum(["csv", "json"]).default("csv").describe("Template format")
|
|
2745
|
+
}
|
|
2746
|
+
},
|
|
2747
|
+
async ({ groupId, versionId, format }) => callApi(
|
|
2748
|
+
"GET",
|
|
2749
|
+
`analytics/groups/${groupId}/versions/${versionId}/dataset-template`,
|
|
2750
|
+
{ params: { format } }
|
|
2751
|
+
)
|
|
2752
|
+
);
|
|
2616
2753
|
}
|
|
2617
2754
|
|
|
2618
2755
|
// src/mcp/tools/history.ts
|
|
2619
2756
|
import { z as z7 } from "zod";
|
|
2620
|
-
function registerHistoryTools(server) {
|
|
2757
|
+
function registerHistoryTools(server, callApi) {
|
|
2621
2758
|
server.registerTool(
|
|
2622
2759
|
"lexq_history_list",
|
|
2623
2760
|
{
|
|
@@ -2679,7 +2816,7 @@ function registerHistoryTools(server) {
|
|
|
2679
2816
|
|
|
2680
2817
|
// src/mcp/tools/integrations.ts
|
|
2681
2818
|
import { z as z8 } from "zod";
|
|
2682
|
-
function registerIntegrationTools(server) {
|
|
2819
|
+
function registerIntegrationTools(server, callApi) {
|
|
2683
2820
|
server.registerTool(
|
|
2684
2821
|
"lexq_integrations_list",
|
|
2685
2822
|
{
|
|
@@ -2752,7 +2889,7 @@ function registerIntegrationTools(server) {
|
|
|
2752
2889
|
|
|
2753
2890
|
// src/mcp/tools/logs.ts
|
|
2754
2891
|
import { z as z9 } from "zod";
|
|
2755
|
-
function registerLogTools(server) {
|
|
2892
|
+
function registerLogTools(server, callApi) {
|
|
2756
2893
|
server.registerTool(
|
|
2757
2894
|
"lexq_logs_list",
|
|
2758
2895
|
{
|
|
@@ -2821,6 +2958,20 @@ function registerLogTools(server) {
|
|
|
2821
2958
|
);
|
|
2822
2959
|
}
|
|
2823
2960
|
|
|
2961
|
+
// src/mcp/register.ts
|
|
2962
|
+
function registerAllTools(server, callApi) {
|
|
2963
|
+
registerStatusTools(server, callApi);
|
|
2964
|
+
registerGroupTools(server, callApi);
|
|
2965
|
+
registerVersionTools(server, callApi);
|
|
2966
|
+
registerRuleTools(server, callApi);
|
|
2967
|
+
registerFactTools(server, callApi);
|
|
2968
|
+
registerDeployTools(server, callApi);
|
|
2969
|
+
registerAnalyticsTools(server, callApi);
|
|
2970
|
+
registerHistoryTools(server, callApi);
|
|
2971
|
+
registerIntegrationTools(server, callApi);
|
|
2972
|
+
registerLogTools(server, callApi);
|
|
2973
|
+
}
|
|
2974
|
+
|
|
2824
2975
|
// src/mcp/server.ts
|
|
2825
2976
|
var __dirname = dirname(fileURLToPath(import.meta.url));
|
|
2826
2977
|
function getVersion() {
|
|
@@ -2838,16 +2989,8 @@ async function startMcpServer() {
|
|
|
2838
2989
|
name: "lexq",
|
|
2839
2990
|
version: getVersion()
|
|
2840
2991
|
});
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
registerVersionTools(server);
|
|
2844
|
-
registerRuleTools(server);
|
|
2845
|
-
registerFactTools(server);
|
|
2846
|
-
registerDeployTools(server);
|
|
2847
|
-
registerAnalyticsTools(server);
|
|
2848
|
-
registerHistoryTools(server);
|
|
2849
|
-
registerIntegrationTools(server);
|
|
2850
|
-
registerLogTools(server);
|
|
2992
|
+
const callApi = createCallApiFromConfig();
|
|
2993
|
+
registerAllTools(server, callApi);
|
|
2851
2994
|
const transport = new StdioServerTransport();
|
|
2852
2995
|
await server.connect(transport);
|
|
2853
2996
|
}
|