@lexq/cli 0.1.30 → 0.1.31

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 CHANGED
@@ -300,13 +300,14 @@ function registerGroupCommands(program) {
300
300
  get Get group detail by ID
301
301
  create Create a new group
302
302
  update Update group settings
303
+ reorder Change group priorities (drag & drag equivalent)
303
304
  delete Archive a group
304
305
  ab-test Manage A/B tests (start, stop, adjust)
305
306
 
306
307
  Statuses: ACTIVE, DISABLED (emergency stop), ARCHIVED (soft delete)
307
308
  `
308
309
  );
309
- groups.command("list").description("List all policy groups").option("--page <number>", "Page number", "0").option("--size <number>", "Page size", "20").action(async (opts) => {
310
+ groups.command("list").description("List all policy groups").action(async () => {
310
311
  try {
311
312
  const globalOpts = program.opts();
312
313
  const format = globalOpts.format ?? "json";
@@ -314,13 +315,12 @@ function registerGroupCommands(program) {
314
315
  apiKey: globalOpts.apiKey,
315
316
  baseUrl: globalOpts.baseUrl,
316
317
  dryRun: globalOpts.dryRun,
317
- verbose: globalOpts.verbose,
318
- params: { page: opts.page, size: opts.size }
318
+ verbose: globalOpts.verbose
319
319
  });
320
320
  if (format === "table") {
321
321
  printTable(
322
322
  ["ID", "Name", "Status", "Priority", "Version", "Updated"],
323
- data.content.map((g) => [
323
+ data.map((g) => [
324
324
  g.id,
325
325
  g.name,
326
326
  g.status,
@@ -331,7 +331,7 @@ function registerGroupCommands(program) {
331
331
  { truncate: 24 }
332
332
  );
333
333
  console.log(`
334
- ${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
334
+ ${data.length} total`);
335
335
  } else {
336
336
  printJson(data);
337
337
  }
@@ -362,19 +362,20 @@ ${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
362
362
  Example:
363
363
  $ lexq groups create --json '{
364
364
  "name": "Payment Policy",
365
- "description": "Rules for payment processing",
366
- "priority": 0
365
+ "description": "Rules for payment processing"
367
366
  }'
368
367
 
369
368
  Fields:
370
369
  name string Group name (required, unique per tenant)
371
370
  description string Description (optional, max 255 chars)
372
- priority number Execution prioritylower runs first (required, min 0)
373
- activationGroup string Cross-group conflict resolution key (optional)
371
+ activationGroup string Execution Groupconflict-resolution cluster key (optional)
374
372
  activationMode string NONE | EXCLUSIVE | MAX_N [default: NONE]
375
373
  activationStrategy string FIRST_MATCH | HIGHEST_PRIORITY | MAX_BENEFIT [default: FIRST_MATCH]
376
374
  executionLimit number Max rules to fire in MAX_N mode (optional)
377
375
  status string ACTIVE | DISABLED [default: ACTIVE]
376
+
377
+ priority is auto-assigned (appended last, tenant-wide). Use 'lexq groups reorder' to change order.
378
+ Groups sharing an activationGroup must share the same activationMode / activationStrategy / executionLimit.
378
379
  `
379
380
  ).action(async (opts) => {
380
381
  try {
@@ -398,9 +399,9 @@ ${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
398
399
  dedent3`
399
400
 
400
401
  Example:
401
- $ lexq groups update --id <groupId> --json '{"description": "Updated", "priority": 1}'
402
+ $ lexq groups update --id <groupId> --json '{"description": "Updated", "status": "DISABLED"}'
402
403
 
403
- All fields are optional — only provided fields are updated.
404
+ All fields are optional — only provided fields are updated. priority is not settable here — use 'lexq groups reorder'.
404
405
  `
405
406
  ).action(async (opts) => {
406
407
  try {
@@ -450,6 +451,41 @@ ${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
450
451
  process.exit(1);
451
452
  }
452
453
  });
454
+ groups.command("reorder").description("Reorder policy groups by priority (drag & drop equivalent)").requiredOption("--group-ids <ids>", "Comma-separated group IDs in desired order").addHelpText(
455
+ "after",
456
+ dedent3`
457
+
458
+ Assigns priority 1, 2, 3, ... to groups in the order given (tenant-wide, 1...N continuous).
459
+ activationGroup (Execution Group) is NOT affected — reorder only changes priority.
460
+
461
+ Example:
462
+ $ lexq groups reorder --group-ids "id3,id1,id2"
463
+
464
+ Result: id3 → priority 1, id1 → priority 2, id2 → priority 3
465
+ `
466
+ ).action(async (opts) => {
467
+ try {
468
+ const globalOpts = program.opts();
469
+ const groupIds = opts.groupIds.split(",").map((id) => id.trim());
470
+ const body = {
471
+ groups: groupIds.map((groupId, index) => ({
472
+ groupId,
473
+ priority: index + 1
474
+ }))
475
+ };
476
+ await apiRequest("PATCH", "policy-groups/reorder", {
477
+ apiKey: globalOpts.apiKey,
478
+ baseUrl: globalOpts.baseUrl,
479
+ dryRun: globalOpts.dryRun,
480
+ verbose: globalOpts.verbose,
481
+ body
482
+ });
483
+ console.log(`\u2713 ${groupIds.length} groups reordered.`);
484
+ } catch (error) {
485
+ printError(error);
486
+ process.exit(1);
487
+ }
488
+ });
453
489
  const abTest = groups.command("ab-test").description("A/B test management").addHelpText(
454
490
  "after",
455
491
  dedent3`
@@ -803,7 +839,7 @@ function registerRuleCommands(program) {
803
839
  Only DRAFT versions allow rule modifications.
804
840
  `
805
841
  );
806
- rules.command("list").description("List rules for a policy version").requiredOption("--group-id <groupId>", "Policy group ID").requiredOption("--version-id <versionId>", "Policy version ID").option("--page <number>", "Page number", "0").option("--size <number>", "Page size", "20").action(async (opts) => {
842
+ rules.command("list").description("List rules for a policy version").requiredOption("--group-id <groupId>", "Policy group ID").requiredOption("--version-id <versionId>", "Policy version ID").action(async (opts) => {
807
843
  try {
808
844
  const globalOpts = program.opts();
809
845
  const format = globalOpts.format ?? "json";
@@ -814,14 +850,13 @@ function registerRuleCommands(program) {
814
850
  apiKey: globalOpts.apiKey,
815
851
  baseUrl: globalOpts.baseUrl,
816
852
  dryRun: globalOpts.dryRun,
817
- verbose: globalOpts.verbose,
818
- params: { page: opts.page, size: opts.size }
853
+ verbose: globalOpts.verbose
819
854
  }
820
855
  );
821
856
  if (format === "table") {
822
857
  printTable(
823
858
  ["ID", "Name", "Priority", "Conditions", "Actions", "Enabled"],
824
- data.content.map((r) => [
859
+ data.map((r) => [
825
860
  r.id,
826
861
  r.name,
827
862
  String(r.priority),
@@ -832,7 +867,7 @@ function registerRuleCommands(program) {
832
867
  { truncate: 24 }
833
868
  );
834
869
  console.log(`
835
- ${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
870
+ ${data.length} total`);
836
871
  } else {
837
872
  printJson(data);
838
873
  }
@@ -867,7 +902,6 @@ ${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
867
902
  Example:
868
903
  $ lexq rules create --group-id <gid> --version-id <vid> --json '{
869
904
  "name": "VIP 20% Discount",
870
- "priority": 0,
871
905
  "condition": {
872
906
  "type": "SINGLE",
873
907
  "field": "customer_tier",
@@ -891,8 +925,11 @@ ${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
891
925
 
892
926
  Mutex (optional — rule-level conflict resolution):
893
927
  mutexGroup string Logical grouping key (e.g., "best-discount")
894
- mutexMode string NONE | EXCLUSIVE [default: NONE]
928
+ mutexMode string NONE | EXCLUSIVE | MAX_N [default: NONE]
895
929
  mutexStrategy string FIRST_MATCH | HIGHEST_PRIORITY | MAX_BENEFIT
930
+ mutexLimit number Max rules to fire in MAX_N mode (required when MAX_N)
931
+
932
+ priority is auto-assigned (appended last). Use 'lexq rules reorder' to change order.
896
933
  `
897
934
  ).action(async (opts) => {
898
935
  try {
@@ -983,12 +1020,12 @@ ${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
983
1020
  "after",
984
1021
  dedent5`
985
1022
 
986
- Assigns priority 0, 1, 2, ... to rules in the order given.
1023
+ Assigns priority 1, 2, 3, ... to rules in the order given (1-based, 1...N continuous).
987
1024
 
988
1025
  Example:
989
1026
  $ lexq rules reorder --group-id <gid> --version-id <vid> --rule-ids "id3,id1,id2"
990
1027
 
991
- Result: id3 → priority 0, id1 → priority 1, id2 → priority 2
1028
+ Result: id3 → priority 1, id1 → priority 2, id2 → priority 3
992
1029
  `
993
1030
  ).action(async (opts) => {
994
1031
  try {
@@ -997,7 +1034,7 @@ ${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
997
1034
  const body = {
998
1035
  rules: ruleIds.map((ruleId, index) => ({
999
1036
  ruleId,
1000
- priority: index
1037
+ priority: index + 1
1001
1038
  }))
1002
1039
  };
1003
1040
  await apiRequest(
@@ -2868,16 +2905,10 @@ function registerGroupTools(server, callApi) {
2868
2905
  "lexq_groups_list",
2869
2906
  {
2870
2907
  title: "List Policy Groups",
2871
- description: "List all policy groups with pagination.",
2872
- inputSchema: {
2873
- page: z.number().int().min(0).default(0).describe("Page number (0-indexed)"),
2874
- size: z.number().int().min(1).max(100).default(20).describe("Page size")
2875
- }
2908
+ description: "List all policy groups (tenant-wide, priority ASC).",
2909
+ inputSchema: {}
2876
2910
  },
2877
- async ({ page, size }) => {
2878
- const params = paginationParams(page, size);
2879
- return callApi("GET", "policy-groups", { params });
2880
- }
2911
+ async () => callApi("GET", "policy-groups")
2881
2912
  );
2882
2913
  server.registerTool(
2883
2914
  "lexq_groups_get",
@@ -2894,10 +2925,9 @@ function registerGroupTools(server, callApi) {
2894
2925
  "lexq_groups_create",
2895
2926
  {
2896
2927
  title: "Create Policy Group",
2897
- description: "Create a new policy group. Requires name and priority. Optionally set conflict resolution, activation group, and description.",
2928
+ description: "Create a new policy group. Requires name. Priority is auto-assigned (appended last, tenant-wide); use lexq_groups_reorder to change order. Optionally set conflict resolution, activation group, and description. Groups sharing an activationGroup must share the same activationMode / activationStrategy / executionLimit.",
2898
2929
  inputSchema: {
2899
2930
  name: z.string().describe("Group name (unique among non-ARCHIVED)"),
2900
- priority: z.number().int().min(0).describe("Execution priority (lower = higher)"),
2901
2931
  description: z.string().optional().describe("Group description"),
2902
2932
  activationMode: z.enum(["NONE", "EXCLUSIVE", "MAX_N"]).optional().describe("Conflict resolution mode"),
2903
2933
  activationStrategy: z.enum(["FIRST_MATCH", "HIGHEST_PRIORITY", "MAX_BENEFIT"]).optional().describe("Strategy when mode is EXCLUSIVE or MAX_N"),
@@ -2907,8 +2937,7 @@ function registerGroupTools(server, callApi) {
2907
2937
  },
2908
2938
  async (args) => {
2909
2939
  const body = {
2910
- name: args.name,
2911
- priority: args.priority
2940
+ name: args.name
2912
2941
  };
2913
2942
  if (args.description !== void 0) body.description = args.description;
2914
2943
  if (args.activationMode !== void 0) body.activationMode = args.activationMode;
@@ -2926,9 +2955,9 @@ function registerGroupTools(server, callApi) {
2926
2955
  inputSchema: {
2927
2956
  groupId: z.string().uuid().describe("Policy group ID"),
2928
2957
  name: z.string().optional().describe("New name"),
2929
- priority: z.number().int().min(0).optional().describe("New priority"),
2930
2958
  description: z.string().optional().describe("New description"),
2931
2959
  status: z.enum(["ACTIVE", "DISABLED"]).optional().describe("Status (DISABLED = emergency stop)"),
2960
+ activationGroup: z.string().optional().describe("Activation group (Execution Group) cluster key"),
2932
2961
  activationMode: z.enum(["NONE", "EXCLUSIVE", "MAX_N"]).optional().describe("Conflict resolution mode"),
2933
2962
  activationStrategy: z.enum(["FIRST_MATCH", "HIGHEST_PRIORITY", "MAX_BENEFIT"]).optional().describe("Strategy"),
2934
2963
  executionLimit: z.number().int().min(1).optional().describe("Max rule executions")
@@ -2947,6 +2976,23 @@ function registerGroupTools(server, callApi) {
2947
2976
  },
2948
2977
  async ({ groupId }) => callApi("DELETE", `policy-groups/${groupId}`)
2949
2978
  );
2979
+ server.registerTool(
2980
+ "lexq_groups_reorder",
2981
+ {
2982
+ title: "Reorder Policy Groups",
2983
+ description: "Reorder policy groups by priority. Priority is tenant-wide and flat (1...N continuous); array index 0 = priority 1 (highest precedence). activationGroup is not affected \u2014 this only changes priority.",
2984
+ inputSchema: {
2985
+ groupIds: z.array(z.string().uuid()).describe("Group IDs in desired priority order (index 0 = priority 1)")
2986
+ }
2987
+ },
2988
+ async ({ groupIds }) => {
2989
+ const groups = groupIds.map((groupId, index) => ({
2990
+ groupId,
2991
+ priority: index + 1
2992
+ }));
2993
+ return callApi("PATCH", "policy-groups/reorder", { body: { groups } });
2994
+ }
2995
+ );
2950
2996
  server.registerTool(
2951
2997
  "lexq_ab_test_start",
2952
2998
  {
@@ -3082,17 +3128,13 @@ function registerRuleTools(server, callApi) {
3082
3128
  "lexq_rules_list",
3083
3129
  {
3084
3130
  title: "List Rules",
3085
- description: "List all rules in a version. Returns summary with conditionSummary and actionSummary.",
3131
+ description: "List all rules in a version (priority ASC). Returns summary with conditionSummary and actionSummary.",
3086
3132
  inputSchema: {
3087
3133
  groupId: z3.string().uuid().describe("Policy group ID"),
3088
- versionId: z3.string().uuid().describe("Version ID"),
3089
- page: z3.number().int().min(0).default(0).describe("Page number"),
3090
- size: z3.number().int().min(1).max(100).default(20).describe("Page size")
3134
+ versionId: z3.string().uuid().describe("Version ID")
3091
3135
  }
3092
3136
  },
3093
- async ({ groupId, versionId, page, size }) => callApi("GET", `policy-groups/${groupId}/versions/${versionId}/rules`, {
3094
- params: paginationParams(page, size)
3095
- })
3137
+ async ({ groupId, versionId }) => callApi("GET", `policy-groups/${groupId}/versions/${versionId}/rules`)
3096
3138
  );
3097
3139
  server.registerTool(
3098
3140
  "lexq_rules_get",
@@ -3112,7 +3154,7 @@ function registerRuleTools(server, callApi) {
3112
3154
  {
3113
3155
  title: "Create Rule",
3114
3156
  description: dedent13`
3115
- Create a rule in a DRAFT version. Requires name, priority, condition tree, and actions array.
3157
+ 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.
3116
3158
 
3117
3159
  Before creating rules with new fact keys, call lexq_facts_list to check existing facts.
3118
3160
  If a required key is missing, ask the user to confirm the type, isRequired, and description
@@ -3145,7 +3187,7 @@ function registerRuleTools(server, callApi) {
3145
3187
  groupId: z3.string().uuid().describe("Policy group ID"),
3146
3188
  versionId: z3.string().uuid().describe("Version ID"),
3147
3189
  rule: z3.string().describe(
3148
- "JSON string of CreateRuleRequest: { name, priority, condition, actions, mutexGroup?, mutexMode?, mutexStrategy?, mutexLimit?, isEnabled? }"
3190
+ "JSON string of CreateRuleRequest: { name, condition, actions, mutexGroup?, mutexMode?, mutexStrategy?, mutexLimit?, isEnabled? }"
3149
3191
  )
3150
3192
  }
3151
3193
  },
@@ -3164,7 +3206,7 @@ function registerRuleTools(server, callApi) {
3164
3206
  versionId: z3.string().uuid().describe("Version ID"),
3165
3207
  ruleId: z3.string().uuid().describe("Rule ID"),
3166
3208
  rule: z3.string().describe(
3167
- "JSON string of UpdateRuleRequest: { name?, priority?, condition?, actions?, mutexGroup?, mutexMode?, mutexStrategy?, mutexLimit?, isEnabled? }"
3209
+ "JSON string of UpdateRuleRequest: { name?, condition?, actions?, mutexGroup?, mutexMode?, mutexStrategy?, mutexLimit?, isEnabled? }"
3168
3210
  )
3169
3211
  }
3170
3212
  },
@@ -3199,7 +3241,7 @@ function registerRuleTools(server, callApi) {
3199
3241
  "lexq_rules_reorder",
3200
3242
  {
3201
3243
  title: "Reorder Rules",
3202
- description: "Reorder rules by specifying rule IDs and their new priorities. Array index 0 = highest priority.",
3244
+ description: "Reorder rules by specifying rule IDs in desired order. Priorities are assigned 1...N (1-based, continuous); array index 0 = priority 1 (highest precedence).",
3203
3245
  inputSchema: {
3204
3246
  groupId: z3.string().uuid().describe("Policy group ID"),
3205
3247
  versionId: z3.string().uuid().describe("Version ID"),
@@ -3209,7 +3251,7 @@ function registerRuleTools(server, callApi) {
3209
3251
  async ({ groupId, versionId, ruleIds }) => {
3210
3252
  const rules = ruleIds.map((ruleId, index) => ({
3211
3253
  ruleId,
3212
- priority: index
3254
+ priority: index + 1
3213
3255
  }));
3214
3256
  return callApi("PATCH", `policy-groups/${groupId}/versions/${versionId}/rules/reorder`, {
3215
3257
  body: { rules }
@@ -13,38 +13,15 @@ function registerStatusTools(server, callApi) {
13
13
 
14
14
  // src/mcp/tools/groups.ts
15
15
  import { z } from "zod";
16
-
17
- // src/lib/config.ts
18
- import { existsSync, mkdirSync, readFileSync, writeFileSync, unlinkSync } from "fs";
19
- import { homedir } from "os";
20
- import { join } from "path";
21
- var CONFIG_DIR = join(homedir(), ".lexq");
22
- var CONFIG_FILE = join(CONFIG_DIR, "config.json");
23
-
24
- // src/mcp/tools/_shared.ts
25
- function paginationParams(page, size) {
26
- const params = {};
27
- if (page !== void 0) params.page = String(page);
28
- if (size !== void 0) params.size = String(size);
29
- return params;
30
- }
31
-
32
- // src/mcp/tools/groups.ts
33
16
  function registerGroupTools(server, callApi) {
34
17
  server.registerTool(
35
18
  "lexq_groups_list",
36
19
  {
37
20
  title: "List Policy Groups",
38
- description: "List all policy groups with pagination.",
39
- inputSchema: {
40
- page: z.number().int().min(0).default(0).describe("Page number (0-indexed)"),
41
- size: z.number().int().min(1).max(100).default(20).describe("Page size")
42
- }
21
+ description: "List all policy groups (tenant-wide, priority ASC).",
22
+ inputSchema: {}
43
23
  },
44
- async ({ page, size }) => {
45
- const params = paginationParams(page, size);
46
- return callApi("GET", "policy-groups", { params });
47
- }
24
+ async () => callApi("GET", "policy-groups")
48
25
  );
49
26
  server.registerTool(
50
27
  "lexq_groups_get",
@@ -61,10 +38,9 @@ function registerGroupTools(server, callApi) {
61
38
  "lexq_groups_create",
62
39
  {
63
40
  title: "Create Policy Group",
64
- description: "Create a new policy group. Requires name and priority. Optionally set conflict resolution, activation group, and description.",
41
+ description: "Create a new policy group. Requires name. Priority is auto-assigned (appended last, tenant-wide); use lexq_groups_reorder to change order. Optionally set conflict resolution, activation group, and description. Groups sharing an activationGroup must share the same activationMode / activationStrategy / executionLimit.",
65
42
  inputSchema: {
66
43
  name: z.string().describe("Group name (unique among non-ARCHIVED)"),
67
- priority: z.number().int().min(0).describe("Execution priority (lower = higher)"),
68
44
  description: z.string().optional().describe("Group description"),
69
45
  activationMode: z.enum(["NONE", "EXCLUSIVE", "MAX_N"]).optional().describe("Conflict resolution mode"),
70
46
  activationStrategy: z.enum(["FIRST_MATCH", "HIGHEST_PRIORITY", "MAX_BENEFIT"]).optional().describe("Strategy when mode is EXCLUSIVE or MAX_N"),
@@ -74,8 +50,7 @@ function registerGroupTools(server, callApi) {
74
50
  },
75
51
  async (args) => {
76
52
  const body = {
77
- name: args.name,
78
- priority: args.priority
53
+ name: args.name
79
54
  };
80
55
  if (args.description !== void 0) body.description = args.description;
81
56
  if (args.activationMode !== void 0) body.activationMode = args.activationMode;
@@ -93,9 +68,9 @@ function registerGroupTools(server, callApi) {
93
68
  inputSchema: {
94
69
  groupId: z.string().uuid().describe("Policy group ID"),
95
70
  name: z.string().optional().describe("New name"),
96
- priority: z.number().int().min(0).optional().describe("New priority"),
97
71
  description: z.string().optional().describe("New description"),
98
72
  status: z.enum(["ACTIVE", "DISABLED"]).optional().describe("Status (DISABLED = emergency stop)"),
73
+ activationGroup: z.string().optional().describe("Activation group (Execution Group) cluster key"),
99
74
  activationMode: z.enum(["NONE", "EXCLUSIVE", "MAX_N"]).optional().describe("Conflict resolution mode"),
100
75
  activationStrategy: z.enum(["FIRST_MATCH", "HIGHEST_PRIORITY", "MAX_BENEFIT"]).optional().describe("Strategy"),
101
76
  executionLimit: z.number().int().min(1).optional().describe("Max rule executions")
@@ -114,6 +89,23 @@ function registerGroupTools(server, callApi) {
114
89
  },
115
90
  async ({ groupId }) => callApi("DELETE", `policy-groups/${groupId}`)
116
91
  );
92
+ server.registerTool(
93
+ "lexq_groups_reorder",
94
+ {
95
+ title: "Reorder Policy Groups",
96
+ description: "Reorder policy groups by priority. Priority is tenant-wide and flat (1...N continuous); array index 0 = priority 1 (highest precedence). activationGroup is not affected \u2014 this only changes priority.",
97
+ inputSchema: {
98
+ groupIds: z.array(z.string().uuid()).describe("Group IDs in desired priority order (index 0 = priority 1)")
99
+ }
100
+ },
101
+ async ({ groupIds }) => {
102
+ const groups = groupIds.map((groupId, index) => ({
103
+ groupId,
104
+ priority: index + 1
105
+ }));
106
+ return callApi("PATCH", "policy-groups/reorder", { body: { groups } });
107
+ }
108
+ );
117
109
  server.registerTool(
118
110
  "lexq_ab_test_start",
119
111
  {
@@ -154,6 +146,23 @@ function registerGroupTools(server, callApi) {
154
146
 
155
147
  // src/mcp/tools/versions.ts
156
148
  import { z as z2 } from "zod";
149
+
150
+ // src/lib/config.ts
151
+ import { existsSync, mkdirSync, readFileSync, writeFileSync, unlinkSync } from "fs";
152
+ import { homedir } from "os";
153
+ import { join } from "path";
154
+ var CONFIG_DIR = join(homedir(), ".lexq");
155
+ var CONFIG_FILE = join(CONFIG_DIR, "config.json");
156
+
157
+ // src/mcp/tools/_shared.ts
158
+ function paginationParams(page, size) {
159
+ const params = {};
160
+ if (page !== void 0) params.page = String(page);
161
+ if (size !== void 0) params.size = String(size);
162
+ return params;
163
+ }
164
+
165
+ // src/mcp/tools/versions.ts
157
166
  function registerVersionTools(server, callApi) {
158
167
  server.registerTool(
159
168
  "lexq_versions_list",
@@ -249,17 +258,13 @@ function registerRuleTools(server, callApi) {
249
258
  "lexq_rules_list",
250
259
  {
251
260
  title: "List Rules",
252
- description: "List all rules in a version. Returns summary with conditionSummary and actionSummary.",
261
+ description: "List all rules in a version (priority ASC). Returns summary with conditionSummary and actionSummary.",
253
262
  inputSchema: {
254
263
  groupId: z3.string().uuid().describe("Policy group ID"),
255
- versionId: z3.string().uuid().describe("Version ID"),
256
- page: z3.number().int().min(0).default(0).describe("Page number"),
257
- size: z3.number().int().min(1).max(100).default(20).describe("Page size")
264
+ versionId: z3.string().uuid().describe("Version ID")
258
265
  }
259
266
  },
260
- async ({ groupId, versionId, page, size }) => callApi("GET", `policy-groups/${groupId}/versions/${versionId}/rules`, {
261
- params: paginationParams(page, size)
262
- })
267
+ async ({ groupId, versionId }) => callApi("GET", `policy-groups/${groupId}/versions/${versionId}/rules`)
263
268
  );
264
269
  server.registerTool(
265
270
  "lexq_rules_get",
@@ -279,7 +284,7 @@ function registerRuleTools(server, callApi) {
279
284
  {
280
285
  title: "Create Rule",
281
286
  description: dedent`
282
- Create a rule in a DRAFT version. Requires name, priority, condition tree, and actions array.
287
+ 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.
283
288
 
284
289
  Before creating rules with new fact keys, call lexq_facts_list to check existing facts.
285
290
  If a required key is missing, ask the user to confirm the type, isRequired, and description
@@ -312,7 +317,7 @@ function registerRuleTools(server, callApi) {
312
317
  groupId: z3.string().uuid().describe("Policy group ID"),
313
318
  versionId: z3.string().uuid().describe("Version ID"),
314
319
  rule: z3.string().describe(
315
- "JSON string of CreateRuleRequest: { name, priority, condition, actions, mutexGroup?, mutexMode?, mutexStrategy?, mutexLimit?, isEnabled? }"
320
+ "JSON string of CreateRuleRequest: { name, condition, actions, mutexGroup?, mutexMode?, mutexStrategy?, mutexLimit?, isEnabled? }"
316
321
  )
317
322
  }
318
323
  },
@@ -331,7 +336,7 @@ function registerRuleTools(server, callApi) {
331
336
  versionId: z3.string().uuid().describe("Version ID"),
332
337
  ruleId: z3.string().uuid().describe("Rule ID"),
333
338
  rule: z3.string().describe(
334
- "JSON string of UpdateRuleRequest: { name?, priority?, condition?, actions?, mutexGroup?, mutexMode?, mutexStrategy?, mutexLimit?, isEnabled? }"
339
+ "JSON string of UpdateRuleRequest: { name?, condition?, actions?, mutexGroup?, mutexMode?, mutexStrategy?, mutexLimit?, isEnabled? }"
335
340
  )
336
341
  }
337
342
  },
@@ -366,7 +371,7 @@ function registerRuleTools(server, callApi) {
366
371
  "lexq_rules_reorder",
367
372
  {
368
373
  title: "Reorder Rules",
369
- description: "Reorder rules by specifying rule IDs and their new priorities. Array index 0 = highest priority.",
374
+ description: "Reorder rules by specifying rule IDs in desired order. Priorities are assigned 1...N (1-based, continuous); array index 0 = priority 1 (highest precedence).",
370
375
  inputSchema: {
371
376
  groupId: z3.string().uuid().describe("Policy group ID"),
372
377
  versionId: z3.string().uuid().describe("Version ID"),
@@ -376,7 +381,7 @@ function registerRuleTools(server, callApi) {
376
381
  async ({ groupId, versionId, ruleIds }) => {
377
382
  const rules = ruleIds.map((ruleId, index) => ({
378
383
  ruleId,
379
- priority: index
384
+ priority: index + 1
380
385
  }));
381
386
  return callApi("PATCH", `policy-groups/${groupId}/versions/${versionId}/rules/reorder`, {
382
387
  body: { rules }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lexq/cli",
3
- "version": "0.1.30",
3
+ "version": "0.1.31",
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": {