@lexq/cli 0.1.37 → 0.1.39
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 +168 -15
- package/dist/mcp/register.d.ts +7 -1
- package/dist/mcp/register.js +60 -8
- package/package.json +7 -5
package/dist/index.js
CHANGED
|
@@ -1358,13 +1358,16 @@ function registerDeployCommands(program) {
|
|
|
1358
1358
|
"after",
|
|
1359
1359
|
dedent7`
|
|
1360
1360
|
|
|
1361
|
-
Lifecycle: Publish (DRAFT→ACTIVE) → Deploy (ACTIVE→LIVE) → Rollback / Undeploy
|
|
1361
|
+
Lifecycle: Publish (DRAFT→ACTIVE) → Deploy or Schedule (ACTIVE→LIVE) → Rollback / Undeploy
|
|
1362
1362
|
|
|
1363
1363
|
Commands:
|
|
1364
1364
|
publish Lock a DRAFT version (DRAFT → ACTIVE)
|
|
1365
1365
|
live Push an ACTIVE version to production traffic
|
|
1366
1366
|
rollback Revert to the previous deployed version
|
|
1367
1367
|
undeploy Remove the live version (stops all traffic)
|
|
1368
|
+
schedule Schedule an ACTIVE version to auto-deploy at its effective start
|
|
1369
|
+
unschedule Cancel the pending scheduled deployment
|
|
1370
|
+
schedules List scheduled deployments (all statuses)
|
|
1368
1371
|
history List deployment history with filters
|
|
1369
1372
|
detail Get deployment detail with integrity check
|
|
1370
1373
|
overview Show all groups' deployment status at a glance
|
|
@@ -1502,10 +1505,7 @@ function registerDeployCommands(program) {
|
|
|
1502
1505
|
process.exit(1);
|
|
1503
1506
|
}
|
|
1504
1507
|
});
|
|
1505
|
-
deploy.command("history").description("List deployment history").option("--group-id <groupId>", "Filter by policy group").option(
|
|
1506
|
-
"--types <types>",
|
|
1507
|
-
"Filter by types (comma-separated: PUBLISH,DEPLOY,ROLLBACK,UNDEPLOY)"
|
|
1508
|
-
).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(
|
|
1508
|
+
deploy.command("history").description("List deployment history").option("--group-id <groupId>", "Filter by policy group").option("--types <types>", "Filter by types (comma-separated: DEPLOY,ROLLBACK,UNDEPLOY)").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(
|
|
1509
1509
|
"after",
|
|
1510
1510
|
dedent7`
|
|
1511
1511
|
|
|
@@ -1660,6 +1660,119 @@ ${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
|
|
|
1660
1660
|
process.exit(1);
|
|
1661
1661
|
}
|
|
1662
1662
|
});
|
|
1663
|
+
deploy.command("schedule").description("Schedule an ACTIVE version to auto-deploy at its effective start").requiredOption("--group-id <groupId>", "Policy group ID").requiredOption("--version-id <versionId>", "Version ID to schedule").requiredOption("--memo <memo>", "Schedule memo").addHelpText(
|
|
1664
|
+
"after",
|
|
1665
|
+
dedent7`
|
|
1666
|
+
|
|
1667
|
+
The version must be ACTIVE with a future effective start date; the system
|
|
1668
|
+
deploys it automatically at that time (within one scheduler tick, ≤60s).
|
|
1669
|
+
One pending schedule per group. Manual deploy/rollback/undeploy, starting
|
|
1670
|
+
an A/B test, or archiving the group cancels the pending schedule.
|
|
1671
|
+
|
|
1672
|
+
Example:
|
|
1673
|
+
$ lexq deploy schedule --group-id <gid> --version-id <vid> --memo "Q4 pricing"
|
|
1674
|
+
`
|
|
1675
|
+
).action(async (opts) => {
|
|
1676
|
+
try {
|
|
1677
|
+
const globalOpts = program.opts();
|
|
1678
|
+
const data = await apiRequest(
|
|
1679
|
+
"POST",
|
|
1680
|
+
`policy-groups/${opts.groupId}/schedule`,
|
|
1681
|
+
{
|
|
1682
|
+
apiKey: globalOpts.apiKey,
|
|
1683
|
+
baseUrl: globalOpts.baseUrl,
|
|
1684
|
+
dryRun: globalOpts.dryRun,
|
|
1685
|
+
verbose: globalOpts.verbose,
|
|
1686
|
+
body: { versionId: opts.versionId, memo: opts.memo }
|
|
1687
|
+
}
|
|
1688
|
+
);
|
|
1689
|
+
console.log(`\u2713 Scheduled v${data.versionNo ?? "?"} for ${data.scheduledFor}.`);
|
|
1690
|
+
} catch (error) {
|
|
1691
|
+
printError(error);
|
|
1692
|
+
process.exit(1);
|
|
1693
|
+
}
|
|
1694
|
+
});
|
|
1695
|
+
deploy.command("unschedule").description("Cancel the pending scheduled deployment for a group").requiredOption("--group-id <groupId>", "Policy group ID").option("--force", "Skip confirmation prompt").addHelpText(
|
|
1696
|
+
"after",
|
|
1697
|
+
dedent7`
|
|
1698
|
+
|
|
1699
|
+
Cancels the PENDING schedule only — the version itself is not affected.
|
|
1700
|
+
|
|
1701
|
+
Example:
|
|
1702
|
+
$ lexq deploy unschedule --group-id <gid> --force
|
|
1703
|
+
`
|
|
1704
|
+
).action(async (opts) => {
|
|
1705
|
+
try {
|
|
1706
|
+
const globalOpts = program.opts();
|
|
1707
|
+
if (!opts.force) {
|
|
1708
|
+
const { createInterface: createInterface2 } = await import("readline/promises");
|
|
1709
|
+
const rl = createInterface2({ input: process.stdin, output: process.stdout });
|
|
1710
|
+
const answer = await rl.question(
|
|
1711
|
+
`Cancel the pending scheduled deployment for group ${opts.groupId}? [y/N] `
|
|
1712
|
+
);
|
|
1713
|
+
rl.close();
|
|
1714
|
+
if (answer.toLowerCase() !== "y") {
|
|
1715
|
+
console.log("Canceled.");
|
|
1716
|
+
return;
|
|
1717
|
+
}
|
|
1718
|
+
}
|
|
1719
|
+
await apiRequest("DELETE", `policy-groups/${opts.groupId}/schedule`, {
|
|
1720
|
+
apiKey: globalOpts.apiKey,
|
|
1721
|
+
baseUrl: globalOpts.baseUrl,
|
|
1722
|
+
dryRun: globalOpts.dryRun,
|
|
1723
|
+
verbose: globalOpts.verbose
|
|
1724
|
+
});
|
|
1725
|
+
console.log(`\u2713 Scheduled deployment canceled for group ${opts.groupId}.`);
|
|
1726
|
+
} catch (error) {
|
|
1727
|
+
printError(error);
|
|
1728
|
+
process.exit(1);
|
|
1729
|
+
}
|
|
1730
|
+
});
|
|
1731
|
+
deploy.command("schedules").description("List scheduled deployments (all statuses, newest first)").option("--page <number>", "Page number", "0").option("--size <number>", "Page size", "20").addHelpText(
|
|
1732
|
+
"after",
|
|
1733
|
+
dedent7`
|
|
1734
|
+
|
|
1735
|
+
Example:
|
|
1736
|
+
$ lexq deploy schedules --format table
|
|
1737
|
+
`
|
|
1738
|
+
).action(async (opts) => {
|
|
1739
|
+
try {
|
|
1740
|
+
const globalOpts = program.opts();
|
|
1741
|
+
const format = globalOpts.format ?? "json";
|
|
1742
|
+
const data = await apiRequest(
|
|
1743
|
+
"GET",
|
|
1744
|
+
"policy-groups/schedules",
|
|
1745
|
+
{
|
|
1746
|
+
apiKey: globalOpts.apiKey,
|
|
1747
|
+
baseUrl: globalOpts.baseUrl,
|
|
1748
|
+
dryRun: globalOpts.dryRun,
|
|
1749
|
+
verbose: globalOpts.verbose,
|
|
1750
|
+
params: { page: opts.page, size: opts.size }
|
|
1751
|
+
}
|
|
1752
|
+
);
|
|
1753
|
+
if (format === "table") {
|
|
1754
|
+
printTable(
|
|
1755
|
+
["Status", "Group", "Version", "Scheduled For", "By", "Result"],
|
|
1756
|
+
data.content.map((s) => [
|
|
1757
|
+
s.status,
|
|
1758
|
+
s.policyGroupName ?? s.policyGroupId.substring(0, 8),
|
|
1759
|
+
s.versionNo != null ? `v${s.versionNo}` : "\u2013",
|
|
1760
|
+
s.scheduledFor.substring(0, 16),
|
|
1761
|
+
s.scheduledByName,
|
|
1762
|
+
s.status === "EXECUTED" ? s.executedAt?.substring(0, 16) ?? "\u2013" : s.status === "CANCELED" ? s.canceledReason ?? "\u2013" : s.status === "FAILED" ? s.failedReason ?? "\u2013" : "\u2013"
|
|
1763
|
+
]),
|
|
1764
|
+
{ truncate: 20 }
|
|
1765
|
+
);
|
|
1766
|
+
console.log(`
|
|
1767
|
+
${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
|
|
1768
|
+
} else {
|
|
1769
|
+
printJson(data);
|
|
1770
|
+
}
|
|
1771
|
+
} catch (error) {
|
|
1772
|
+
printError(error);
|
|
1773
|
+
process.exit(1);
|
|
1774
|
+
}
|
|
1775
|
+
});
|
|
1663
1776
|
}
|
|
1664
1777
|
async function warnUnregisteredFacts(globalOpts, groupId, versionId) {
|
|
1665
1778
|
if (globalOpts.dryRun) return;
|
|
@@ -2206,13 +2319,16 @@ var TaskType = [
|
|
|
2206
2319
|
// Internal
|
|
2207
2320
|
"IMAGE_PROCESSING",
|
|
2208
2321
|
"DAILY_SETTLEMENT",
|
|
2209
|
-
"PLATFORM_WEBHOOK"
|
|
2322
|
+
"PLATFORM_WEBHOOK",
|
|
2323
|
+
"SCHEDULED_DEPLOYMENT"
|
|
2210
2324
|
];
|
|
2211
2325
|
var PlatformEventType = [
|
|
2212
2326
|
"VERSION_PUBLISHED",
|
|
2213
2327
|
"DEPLOYED",
|
|
2214
2328
|
"ROLLED_BACK",
|
|
2215
|
-
"UNDEPLOYED"
|
|
2329
|
+
"UNDEPLOYED",
|
|
2330
|
+
"DEPLOY_SCHEDULED",
|
|
2331
|
+
"DEPLOY_SCHEDULE_CANCELED"
|
|
2216
2332
|
];
|
|
2217
2333
|
var WebhookPayloadFormat = ["GENERIC", "SLACK"];
|
|
2218
2334
|
|
|
@@ -2226,8 +2342,9 @@ function registerProfileCommands(program) {
|
|
|
2226
2342
|
|
|
2227
2343
|
Slow-rule judgment is relative only: flagged = p50 ≥ 10× the median of
|
|
2228
2344
|
per-rule p50s within the group. Absolute ms thresholds are intentionally
|
|
2229
|
-
not supported.
|
|
2230
|
-
|
|
2345
|
+
not supported. Each percentile is withheld (–) unless n×(1−q) ≥ 3 —
|
|
2346
|
+
p50 from n ≥ 6, p95 from n ≥ 60, p99 from n ≥ 300. TOTAL is recorded
|
|
2347
|
+
on every call, rule detail from a deterministic 1% sample.
|
|
2231
2348
|
|
|
2232
2349
|
Examples:
|
|
2233
2350
|
$ lexq profile <groupId>
|
|
@@ -3816,7 +3933,7 @@ function registerDeployTools(server, callApi) {
|
|
|
3816
3933
|
"lexq_deploy_live",
|
|
3817
3934
|
{
|
|
3818
3935
|
title: "Deploy to Live",
|
|
3819
|
-
description: "Deploy an ACTIVE (published) version to live traffic. Takes effect immediately. Undefined facts do not block deployment (INV-4); use lexq_facts_unregistered to review what the version references but has not defined.",
|
|
3936
|
+
description: "Deploy an ACTIVE (published) version to live traffic. Takes effect immediately. Versions whose effective start date has not arrived are rejected (P-037) \u2014 use lexq_deploy_schedule for those. Undefined facts do not block deployment (INV-4); use lexq_facts_unregistered to review what the version references but has not defined.",
|
|
3820
3937
|
inputSchema: {
|
|
3821
3938
|
groupId: z5.string().uuid().describe("Policy group ID"),
|
|
3822
3939
|
versionId: z5.string().uuid().describe("Version ID to deploy"),
|
|
@@ -3855,6 +3972,44 @@ function registerDeployTools(server, callApi) {
|
|
|
3855
3972
|
body: { memo }
|
|
3856
3973
|
})
|
|
3857
3974
|
);
|
|
3975
|
+
server.registerTool(
|
|
3976
|
+
"lexq_deploy_schedule",
|
|
3977
|
+
{
|
|
3978
|
+
title: "Schedule Deployment",
|
|
3979
|
+
description: "Schedule an ACTIVE version with a future effective start date to auto-deploy at that time (Scheduled Deployment). One pending schedule per group; manual deploy/rollback/undeploy, starting an A/B test, or archiving the group cancels it. The snapshot hash is sealed at scheduling and re-verified at execution (fail-closed).",
|
|
3980
|
+
inputSchema: {
|
|
3981
|
+
groupId: z5.string().uuid().describe("Policy group ID"),
|
|
3982
|
+
versionId: z5.string().uuid().describe("ACTIVE version ID with a future effective start date"),
|
|
3983
|
+
memo: z5.string().min(1).describe("Schedule memo (required)")
|
|
3984
|
+
}
|
|
3985
|
+
},
|
|
3986
|
+
async ({ groupId, versionId, memo }) => callApi("POST", `policy-groups/${groupId}/schedule`, {
|
|
3987
|
+
body: { versionId, memo }
|
|
3988
|
+
})
|
|
3989
|
+
);
|
|
3990
|
+
server.registerTool(
|
|
3991
|
+
"lexq_deploy_unschedule",
|
|
3992
|
+
{
|
|
3993
|
+
title: "Cancel Scheduled Deployment",
|
|
3994
|
+
description: "Cancel the pending scheduled deployment for a group. The version itself is not affected. Fails with P-039 if no pending schedule exists.",
|
|
3995
|
+
inputSchema: {
|
|
3996
|
+
groupId: z5.string().uuid().describe("Policy group ID")
|
|
3997
|
+
}
|
|
3998
|
+
},
|
|
3999
|
+
async ({ groupId }) => callApi("DELETE", `policy-groups/${groupId}/schedule`)
|
|
4000
|
+
);
|
|
4001
|
+
server.registerTool(
|
|
4002
|
+
"lexq_deploy_schedules",
|
|
4003
|
+
{
|
|
4004
|
+
title: "List Scheduled Deployments",
|
|
4005
|
+
description: "List scheduled deployments across all groups (all statuses: PENDING, EXECUTED, CANCELED, FAILED), newest first.",
|
|
4006
|
+
inputSchema: {
|
|
4007
|
+
page: z5.number().int().min(0).default(0).describe("Page number"),
|
|
4008
|
+
size: z5.number().int().min(1).max(100).default(20).describe("Page size")
|
|
4009
|
+
}
|
|
4010
|
+
},
|
|
4011
|
+
async ({ page, size }) => callApi("GET", "policy-groups/schedules", { params: paginationParams(page, size) })
|
|
4012
|
+
);
|
|
3858
4013
|
server.registerTool(
|
|
3859
4014
|
"lexq_deploy_history",
|
|
3860
4015
|
{
|
|
@@ -3864,9 +4019,7 @@ function registerDeployTools(server, callApi) {
|
|
|
3864
4019
|
page: z5.number().int().min(0).default(0).describe("Page number"),
|
|
3865
4020
|
size: z5.number().int().min(1).max(100).default(20).describe("Page size"),
|
|
3866
4021
|
groupId: z5.string().uuid().optional().describe("Filter by group ID"),
|
|
3867
|
-
types: z5.string().optional().describe(
|
|
3868
|
-
"Filter by deployment types (comma-separated: PUBLISH,DEPLOY,ROLLBACK,UNDEPLOY)"
|
|
3869
|
-
),
|
|
4022
|
+
types: z5.string().optional().describe("Filter by deployment types (comma-separated: DEPLOY,ROLLBACK,UNDEPLOY)"),
|
|
3870
4023
|
startDate: z5.string().optional().describe("Start date (yyyy-MM-dd)"),
|
|
3871
4024
|
endDate: z5.string().optional().describe("End date (yyyy-MM-dd)")
|
|
3872
4025
|
}
|
|
@@ -4171,7 +4324,7 @@ function registerProfileTools(server, callApi) {
|
|
|
4171
4324
|
"lexq_profile_overview",
|
|
4172
4325
|
{
|
|
4173
4326
|
title: "Group Latency Profile",
|
|
4174
|
-
description: "Per-rule latency profile of a policy group over a time window: group TOTAL distribution split by cache state (HIT = compiled ruleset cache hit, MISS = deep-load + compile), a per-rule CONDITION/ACTION percentile table, and slow-rule flags. " + RELATIVE_THRESHOLD + " Every percentile is accompanied by its sample count n;
|
|
4327
|
+
description: "Per-rule latency profile of a policy group over a time window: group TOTAL distribution split by cache state (HIT = compiled ruleset cache hit, MISS = deep-load + compile), a per-rule CONDITION/ACTION percentile table, and slow-rule flags. " + RELATIVE_THRESHOLD + " Every percentile is accompanied by its sample count n; a percentile is withheld (null) unless n\xD7(1\u2212q) \u2265 3 (p50 needs n \u2265 6, p95 n \u2265 60, p99 n \u2265 300 \u2014 display gate, separate from the n \u2265 100 judgment gate). Baselines report INSUFFICIENT_COHORT when fewer than 3 rules qualify. Rule detail comes from a deterministic 1% sample of calls; TOTAL is recorded for every call. Defaults: last 24h, live version, cacheState HIT.",
|
|
4175
4328
|
inputSchema: {
|
|
4176
4329
|
groupId: z7.string().uuid().describe("Policy group ID"),
|
|
4177
4330
|
versionId: z7.string().uuid().optional().describe("Version to inspect (default: live version)"),
|
|
@@ -4188,7 +4341,7 @@ function registerProfileTools(server, callApi) {
|
|
|
4188
4341
|
"lexq_profile_rule",
|
|
4189
4342
|
{
|
|
4190
4343
|
title: "Rule Latency Detail",
|
|
4191
|
-
description: "Single-rule latency detail: merged phase \xD7 cacheState distributions plus a per-window time series (60s windows). Missing windows are genuine gaps \u2014 never interpolated. Series points carry each window's own values; percentiles in merged distributions are withheld (null)
|
|
4344
|
+
description: "Single-rule latency detail: merged phase \xD7 cacheState distributions plus a per-window time series (60s windows). Missing windows are genuine gaps \u2014 never interpolated. Series points carry each window's own values; percentiles in merged distributions are withheld (null) unless n\xD7(1\u2212q) \u2265 3 (p50 n \u2265 6, p95 n \u2265 60, p99 n \u2265 300). " + RELATIVE_THRESHOLD,
|
|
4192
4345
|
inputSchema: {
|
|
4193
4346
|
groupId: z7.string().uuid().describe("Policy group ID"),
|
|
4194
4347
|
ruleId: z7.string().uuid().describe("Rule ID (from lexq_profile_overview)"),
|
package/dist/mcp/register.d.ts
CHANGED
|
@@ -35,6 +35,12 @@ declare function paginationParams(page?: number, size?: number): Record<string,
|
|
|
35
35
|
*/
|
|
36
36
|
declare function formatUnregisteredFactWarning(meta: unknown): string | null;
|
|
37
37
|
|
|
38
|
+
declare class ApiError extends Error {
|
|
39
|
+
readonly statusCode: number;
|
|
40
|
+
readonly errorCode: string | null;
|
|
41
|
+
constructor(statusCode: number, errorCode: string | null, message: string);
|
|
42
|
+
}
|
|
43
|
+
|
|
38
44
|
/**
|
|
39
45
|
* Registers all MCP tools on the given server.
|
|
40
46
|
*
|
|
@@ -43,4 +49,4 @@ declare function formatUnregisteredFactWarning(meta: unknown): string | null;
|
|
|
43
49
|
*/
|
|
44
50
|
declare function registerAllTools(server: McpServer, callApi: CallApi): void;
|
|
45
51
|
|
|
46
|
-
export { type CallApi, type McpToolResult, formatUnregisteredFactWarning, paginationParams, registerAllTools };
|
|
52
|
+
export { ApiError, type CallApi, type McpToolResult, formatUnregisteredFactWarning, paginationParams, registerAllTools };
|
package/dist/mcp/register.js
CHANGED
|
@@ -154,6 +154,18 @@ import { join } from "path";
|
|
|
154
154
|
var CONFIG_DIR = join(homedir(), ".lexq");
|
|
155
155
|
var CONFIG_FILE = join(CONFIG_DIR, "config.json");
|
|
156
156
|
|
|
157
|
+
// src/lib/api-client.ts
|
|
158
|
+
var ApiError = class extends Error {
|
|
159
|
+
constructor(statusCode, errorCode, message) {
|
|
160
|
+
super(message);
|
|
161
|
+
this.statusCode = statusCode;
|
|
162
|
+
this.errorCode = errorCode;
|
|
163
|
+
this.name = "ApiError";
|
|
164
|
+
}
|
|
165
|
+
statusCode;
|
|
166
|
+
errorCode;
|
|
167
|
+
};
|
|
168
|
+
|
|
157
169
|
// src/mcp/tools/_shared.ts
|
|
158
170
|
function paginationParams(page, size) {
|
|
159
171
|
const params = {};
|
|
@@ -532,7 +544,7 @@ function registerDeployTools(server, callApi) {
|
|
|
532
544
|
"lexq_deploy_live",
|
|
533
545
|
{
|
|
534
546
|
title: "Deploy to Live",
|
|
535
|
-
description: "Deploy an ACTIVE (published) version to live traffic. Takes effect immediately. Undefined facts do not block deployment (INV-4); use lexq_facts_unregistered to review what the version references but has not defined.",
|
|
547
|
+
description: "Deploy an ACTIVE (published) version to live traffic. Takes effect immediately. Versions whose effective start date has not arrived are rejected (P-037) \u2014 use lexq_deploy_schedule for those. Undefined facts do not block deployment (INV-4); use lexq_facts_unregistered to review what the version references but has not defined.",
|
|
536
548
|
inputSchema: {
|
|
537
549
|
groupId: z5.string().uuid().describe("Policy group ID"),
|
|
538
550
|
versionId: z5.string().uuid().describe("Version ID to deploy"),
|
|
@@ -571,6 +583,44 @@ function registerDeployTools(server, callApi) {
|
|
|
571
583
|
body: { memo }
|
|
572
584
|
})
|
|
573
585
|
);
|
|
586
|
+
server.registerTool(
|
|
587
|
+
"lexq_deploy_schedule",
|
|
588
|
+
{
|
|
589
|
+
title: "Schedule Deployment",
|
|
590
|
+
description: "Schedule an ACTIVE version with a future effective start date to auto-deploy at that time (Scheduled Deployment). One pending schedule per group; manual deploy/rollback/undeploy, starting an A/B test, or archiving the group cancels it. The snapshot hash is sealed at scheduling and re-verified at execution (fail-closed).",
|
|
591
|
+
inputSchema: {
|
|
592
|
+
groupId: z5.string().uuid().describe("Policy group ID"),
|
|
593
|
+
versionId: z5.string().uuid().describe("ACTIVE version ID with a future effective start date"),
|
|
594
|
+
memo: z5.string().min(1).describe("Schedule memo (required)")
|
|
595
|
+
}
|
|
596
|
+
},
|
|
597
|
+
async ({ groupId, versionId, memo }) => callApi("POST", `policy-groups/${groupId}/schedule`, {
|
|
598
|
+
body: { versionId, memo }
|
|
599
|
+
})
|
|
600
|
+
);
|
|
601
|
+
server.registerTool(
|
|
602
|
+
"lexq_deploy_unschedule",
|
|
603
|
+
{
|
|
604
|
+
title: "Cancel Scheduled Deployment",
|
|
605
|
+
description: "Cancel the pending scheduled deployment for a group. The version itself is not affected. Fails with P-039 if no pending schedule exists.",
|
|
606
|
+
inputSchema: {
|
|
607
|
+
groupId: z5.string().uuid().describe("Policy group ID")
|
|
608
|
+
}
|
|
609
|
+
},
|
|
610
|
+
async ({ groupId }) => callApi("DELETE", `policy-groups/${groupId}/schedule`)
|
|
611
|
+
);
|
|
612
|
+
server.registerTool(
|
|
613
|
+
"lexq_deploy_schedules",
|
|
614
|
+
{
|
|
615
|
+
title: "List Scheduled Deployments",
|
|
616
|
+
description: "List scheduled deployments across all groups (all statuses: PENDING, EXECUTED, CANCELED, FAILED), newest first.",
|
|
617
|
+
inputSchema: {
|
|
618
|
+
page: z5.number().int().min(0).default(0).describe("Page number"),
|
|
619
|
+
size: z5.number().int().min(1).max(100).default(20).describe("Page size")
|
|
620
|
+
}
|
|
621
|
+
},
|
|
622
|
+
async ({ page, size }) => callApi("GET", "policy-groups/schedules", { params: paginationParams(page, size) })
|
|
623
|
+
);
|
|
574
624
|
server.registerTool(
|
|
575
625
|
"lexq_deploy_history",
|
|
576
626
|
{
|
|
@@ -580,9 +630,7 @@ function registerDeployTools(server, callApi) {
|
|
|
580
630
|
page: z5.number().int().min(0).default(0).describe("Page number"),
|
|
581
631
|
size: z5.number().int().min(1).max(100).default(20).describe("Page size"),
|
|
582
632
|
groupId: z5.string().uuid().optional().describe("Filter by group ID"),
|
|
583
|
-
types: z5.string().optional().describe(
|
|
584
|
-
"Filter by deployment types (comma-separated: PUBLISH,DEPLOY,ROLLBACK,UNDEPLOY)"
|
|
585
|
-
),
|
|
633
|
+
types: z5.string().optional().describe("Filter by deployment types (comma-separated: DEPLOY,ROLLBACK,UNDEPLOY)"),
|
|
586
634
|
startDate: z5.string().optional().describe("Start date (yyyy-MM-dd)"),
|
|
587
635
|
endDate: z5.string().optional().describe("End date (yyyy-MM-dd)")
|
|
588
636
|
}
|
|
@@ -887,7 +935,7 @@ function registerProfileTools(server, callApi) {
|
|
|
887
935
|
"lexq_profile_overview",
|
|
888
936
|
{
|
|
889
937
|
title: "Group Latency Profile",
|
|
890
|
-
description: "Per-rule latency profile of a policy group over a time window: group TOTAL distribution split by cache state (HIT = compiled ruleset cache hit, MISS = deep-load + compile), a per-rule CONDITION/ACTION percentile table, and slow-rule flags. " + RELATIVE_THRESHOLD + " Every percentile is accompanied by its sample count n;
|
|
938
|
+
description: "Per-rule latency profile of a policy group over a time window: group TOTAL distribution split by cache state (HIT = compiled ruleset cache hit, MISS = deep-load + compile), a per-rule CONDITION/ACTION percentile table, and slow-rule flags. " + RELATIVE_THRESHOLD + " Every percentile is accompanied by its sample count n; a percentile is withheld (null) unless n\xD7(1\u2212q) \u2265 3 (p50 needs n \u2265 6, p95 n \u2265 60, p99 n \u2265 300 \u2014 display gate, separate from the n \u2265 100 judgment gate). Baselines report INSUFFICIENT_COHORT when fewer than 3 rules qualify. Rule detail comes from a deterministic 1% sample of calls; TOTAL is recorded for every call. Defaults: last 24h, live version, cacheState HIT.",
|
|
891
939
|
inputSchema: {
|
|
892
940
|
groupId: z7.string().uuid().describe("Policy group ID"),
|
|
893
941
|
versionId: z7.string().uuid().optional().describe("Version to inspect (default: live version)"),
|
|
@@ -904,7 +952,7 @@ function registerProfileTools(server, callApi) {
|
|
|
904
952
|
"lexq_profile_rule",
|
|
905
953
|
{
|
|
906
954
|
title: "Rule Latency Detail",
|
|
907
|
-
description: "Single-rule latency detail: merged phase \xD7 cacheState distributions plus a per-window time series (60s windows). Missing windows are genuine gaps \u2014 never interpolated. Series points carry each window's own values; percentiles in merged distributions are withheld (null)
|
|
955
|
+
description: "Single-rule latency detail: merged phase \xD7 cacheState distributions plus a per-window time series (60s windows). Missing windows are genuine gaps \u2014 never interpolated. Series points carry each window's own values; percentiles in merged distributions are withheld (null) unless n\xD7(1\u2212q) \u2265 3 (p50 n \u2265 6, p95 n \u2265 60, p99 n \u2265 300). " + RELATIVE_THRESHOLD,
|
|
908
956
|
inputSchema: {
|
|
909
957
|
groupId: z7.string().uuid().describe("Policy group ID"),
|
|
910
958
|
ruleId: z7.string().uuid().describe("Rule ID (from lexq_profile_overview)"),
|
|
@@ -1182,13 +1230,16 @@ var TaskType = [
|
|
|
1182
1230
|
// Internal
|
|
1183
1231
|
"IMAGE_PROCESSING",
|
|
1184
1232
|
"DAILY_SETTLEMENT",
|
|
1185
|
-
"PLATFORM_WEBHOOK"
|
|
1233
|
+
"PLATFORM_WEBHOOK",
|
|
1234
|
+
"SCHEDULED_DEPLOYMENT"
|
|
1186
1235
|
];
|
|
1187
1236
|
var PlatformEventType = [
|
|
1188
1237
|
"VERSION_PUBLISHED",
|
|
1189
1238
|
"DEPLOYED",
|
|
1190
1239
|
"ROLLED_BACK",
|
|
1191
|
-
"UNDEPLOYED"
|
|
1240
|
+
"UNDEPLOYED",
|
|
1241
|
+
"DEPLOY_SCHEDULED",
|
|
1242
|
+
"DEPLOY_SCHEDULE_CANCELED"
|
|
1192
1243
|
];
|
|
1193
1244
|
var WebhookPayloadFormat = ["GENERIC", "SLACK"];
|
|
1194
1245
|
|
|
@@ -1396,6 +1447,7 @@ function registerAllTools(server, callApi) {
|
|
|
1396
1447
|
registerWebhookSubscriptionTools(server, callApi);
|
|
1397
1448
|
}
|
|
1398
1449
|
export {
|
|
1450
|
+
ApiError,
|
|
1399
1451
|
formatUnregisteredFactWarning,
|
|
1400
1452
|
paginationParams,
|
|
1401
1453
|
registerAllTools
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lexq/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.39",
|
|
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": {
|
|
@@ -29,7 +29,10 @@
|
|
|
29
29
|
"lint": "eslint src/",
|
|
30
30
|
"typecheck": "tsc --noEmit",
|
|
31
31
|
"start": "node dist/index.js",
|
|
32
|
-
"prepublishOnly": "pnpm build"
|
|
32
|
+
"prepublishOnly": "pnpm build",
|
|
33
|
+
"knip": "knip",
|
|
34
|
+
"format": "prettier --write \"src/**/*.ts\"",
|
|
35
|
+
"format:check": "prettier --check \"src/**/*.ts\""
|
|
33
36
|
},
|
|
34
37
|
"keywords": [
|
|
35
38
|
"lexq",
|
|
@@ -57,15 +60,14 @@
|
|
|
57
60
|
"cli-table3": "^0.6.5",
|
|
58
61
|
"commander": "^13.1.0",
|
|
59
62
|
"dedent": "^1.7.2",
|
|
60
|
-
"ora": "^8.2.0",
|
|
61
|
-
"prettier": "^3.8.1",
|
|
62
63
|
"zod": "^3.25.76"
|
|
63
64
|
},
|
|
64
65
|
"devDependencies": {
|
|
65
66
|
"@eslint/js": "^9.20.0",
|
|
66
|
-
"@types/dedent": "^0.7.2",
|
|
67
67
|
"@types/node": "^22.12.0",
|
|
68
68
|
"eslint": "^10.2.0",
|
|
69
|
+
"knip": "^6.29.0",
|
|
70
|
+
"prettier": "^3.9.6",
|
|
69
71
|
"tsup": "^8.5.1",
|
|
70
72
|
"typescript": "^5.7.0",
|
|
71
73
|
"typescript-eslint": "^8.24.0"
|