@cruxy/cli 0.18.0 → 0.20.0

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.
Files changed (61) hide show
  1. package/dist/agent/loop.d.ts +12 -0
  2. package/dist/agent/loop.js +20 -0
  3. package/dist/agent/session.d.ts +18 -1
  4. package/dist/agent/session.js +38 -6
  5. package/dist/cli/commands/run.js +31 -1
  6. package/dist/cli/commands/usage.d.ts +9 -0
  7. package/dist/cli/commands/usage.js +81 -0
  8. package/dist/cli/program.js +2 -0
  9. package/dist/cli/session-factory.js +30 -1
  10. package/dist/config/schema.d.ts +407 -14
  11. package/dist/config/schema.js +77 -0
  12. package/dist/constants.d.ts +7 -0
  13. package/dist/constants.js +7 -0
  14. package/dist/errors/constructors.d.ts +30 -0
  15. package/dist/errors/constructors.js +86 -0
  16. package/dist/errors/types.d.ts +13 -0
  17. package/dist/errors/types.js +25 -0
  18. package/dist/lsp/client.d.ts +25 -0
  19. package/dist/lsp/client.js +43 -0
  20. package/dist/lsp/index.d.ts +8 -0
  21. package/dist/lsp/index.js +8 -0
  22. package/dist/lsp/pool.d.ts +48 -0
  23. package/dist/lsp/pool.js +132 -0
  24. package/dist/lsp/registry.d.ts +38 -0
  25. package/dist/lsp/registry.js +133 -0
  26. package/dist/lsp/server.d.ts +48 -0
  27. package/dist/lsp/server.js +264 -0
  28. package/dist/lsp/service.d.ts +44 -0
  29. package/dist/lsp/service.js +76 -0
  30. package/dist/lsp/tools/common.d.ts +23 -0
  31. package/dist/lsp/tools/common.js +75 -0
  32. package/dist/lsp/tools/find-definition.d.ts +23 -0
  33. package/dist/lsp/tools/find-definition.js +41 -0
  34. package/dist/lsp/tools/find-references.d.ts +23 -0
  35. package/dist/lsp/tools/find-references.js +41 -0
  36. package/dist/lsp/tools/get-diagnostics.d.ts +17 -0
  37. package/dist/lsp/tools/get-diagnostics.js +43 -0
  38. package/dist/lsp/tools/hover.d.ts +23 -0
  39. package/dist/lsp/tools/hover.js +38 -0
  40. package/dist/lsp/tools/index.d.ts +4 -0
  41. package/dist/lsp/tools/index.js +4 -0
  42. package/dist/lsp/transport.d.ts +48 -0
  43. package/dist/lsp/transport.js +264 -0
  44. package/dist/lsp/types.d.ts +107 -0
  45. package/dist/lsp/types.js +1 -0
  46. package/dist/plan/service.d.ts +10 -1
  47. package/dist/plan/service.js +2 -0
  48. package/dist/tools/file/grep-files.d.ts +2 -2
  49. package/dist/usage/collect.d.ts +40 -0
  50. package/dist/usage/collect.js +34 -0
  51. package/dist/usage/cost.d.ts +19 -0
  52. package/dist/usage/cost.js +29 -0
  53. package/dist/usage/index.d.ts +15 -0
  54. package/dist/usage/index.js +15 -0
  55. package/dist/usage/store.d.ts +37 -0
  56. package/dist/usage/store.js +83 -0
  57. package/dist/usage/summary.d.ts +32 -0
  58. package/dist/usage/summary.js +119 -0
  59. package/dist/usage/types.d.ts +220 -0
  60. package/dist/usage/types.js +47 -0
  61. package/package.json +1 -1
@@ -236,8 +236,8 @@ export declare const TestConfigSchema: z.ZodObject<{
236
236
  captureBytes: number;
237
237
  command?: string | undefined;
238
238
  }, {
239
- maxIterations?: number | undefined;
240
239
  command?: string | undefined;
240
+ maxIterations?: number | undefined;
241
241
  captureBytes?: number | undefined;
242
242
  }>;
243
243
  /**
@@ -264,9 +264,9 @@ export declare const SubagentConfigSchema: z.ZodObject<{
264
264
  maxIterations: number;
265
265
  timeoutMs?: number | undefined;
266
266
  }, {
267
+ timeoutMs?: number | undefined;
267
268
  maxTokens?: number | undefined;
268
269
  maxIterations?: number | undefined;
269
- timeoutMs?: number | undefined;
270
270
  }>>;
271
271
  }, "strict", z.ZodTypeAny, {
272
272
  maxDepth: number;
@@ -278,9 +278,9 @@ export declare const SubagentConfigSchema: z.ZodObject<{
278
278
  }, {
279
279
  maxDepth?: number | undefined;
280
280
  defaultBudget?: {
281
+ timeoutMs?: number | undefined;
281
282
  maxTokens?: number | undefined;
282
283
  maxIterations?: number | undefined;
283
- timeoutMs?: number | undefined;
284
284
  } | undefined;
285
285
  }>;
286
286
  /**
@@ -408,6 +408,191 @@ export declare const MemoryConfigSchema: z.ZodObject<{
408
408
  maxRecallTokens?: number | undefined;
409
409
  }>;
410
410
  export type MemoryConfig = z.infer<typeof MemoryConfigSchema>;
411
+ /**
412
+ * Per-language LSP integration (C.12): read-only, symbol-aware tools
413
+ * (find_definition, find_references, get_diagnostics, hover) backed by a
414
+ * managed pool of language servers. OFF by default — like the sandbox and
415
+ * hooks, it spawns and manages EXTERNAL server processes, a real execution
416
+ * surface the user opts into explicitly. When on, a missing server binary is
417
+ * an actionable, coded failure (CRUXY_E_LSP_SERVER_NOT_FOUND), never a silent
418
+ * empty result. Servers spawn lazily per language, are reused for the session,
419
+ * and are shut down cleanly (with a process-exit kill-tree backstop).
420
+ */
421
+ export declare const LspConfigSchema: z.ZodObject<{
422
+ /** Master switch. When false, the four LSP tools are not registered and no
423
+ * server ever spawns (the feature stays fully inert). */
424
+ enabled: z.ZodDefault<z.ZodBoolean>;
425
+ /**
426
+ * Per-language command overrides, keyed by language id (e.g. `typescript`,
427
+ * `python`, `go`, `rust`). The value is the full command line
428
+ * (`"gopls -remote=auto"`); it is split on whitespace. Anything omitted
429
+ * falls back to the built-in default table (see `lsp/registry.ts`).
430
+ */
431
+ servers: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodString>>;
432
+ /** Kill and fail (CRUXY_E_LSP_TIMEOUT) if the `initialize` handshake does
433
+ * not complete within this many ms. */
434
+ startupTimeout: z.ZodDefault<z.ZodNumber>;
435
+ /** Fail a single query (CRUXY_E_LSP_TIMEOUT) if the server does not respond
436
+ * within this many ms — the server is kept alive, only the request errors. */
437
+ requestTimeout: z.ZodDefault<z.ZodNumber>;
438
+ /** Maximum concurrently-running language servers; acquiring past the cap
439
+ * evicts the idle-oldest server first. */
440
+ maxServers: z.ZodDefault<z.ZodNumber>;
441
+ /** Shut a server down after it has been idle this many ms. */
442
+ idleTimeout: z.ZodDefault<z.ZodNumber>;
443
+ /** Cap on locations/diagnostics returned by a single tool call; the rest are
444
+ * summarized as an "N more" note (bounded output). */
445
+ maxResults: z.ZodDefault<z.ZodNumber>;
446
+ }, "strict", z.ZodTypeAny, {
447
+ startupTimeout: number;
448
+ requestTimeout: number;
449
+ enabled: boolean;
450
+ servers: Record<string, string>;
451
+ maxServers: number;
452
+ idleTimeout: number;
453
+ maxResults: number;
454
+ }, {
455
+ startupTimeout?: number | undefined;
456
+ requestTimeout?: number | undefined;
457
+ enabled?: boolean | undefined;
458
+ servers?: Record<string, string> | undefined;
459
+ maxServers?: number | undefined;
460
+ idleTimeout?: number | undefined;
461
+ maxResults?: number | undefined;
462
+ }>;
463
+ export type LspConfig = z.infer<typeof LspConfigSchema>;
464
+ /** A per-tier price, in the user's own currency, PER MILLION TOKENS (C.22). */
465
+ export declare const TierPriceSchema: z.ZodObject<{
466
+ /** Price per 1,000,000 input tokens. */
467
+ input: z.ZodNumber;
468
+ /** Price per 1,000,000 output tokens. */
469
+ output: z.ZodNumber;
470
+ }, "strict", z.ZodTypeAny, {
471
+ input: number;
472
+ output: number;
473
+ }, {
474
+ input: number;
475
+ output: number;
476
+ }>;
477
+ /**
478
+ * Usage telemetry + cost tracking (C.22): LOCAL usage accounting only — nothing
479
+ * here is ever transmitted. Costs are opt-in and honest: prices are per-TIER and
480
+ * per-million-tokens, configured by the user; with none set, tokens are shown
481
+ * and cost is omitted (cruxy ships no bundled price table). The `prices` keys are
482
+ * the fixed {@link MODEL_TIERS}, so an upstream model name can never appear here
483
+ * (U.8 gag holds by construction) and a mistyped tier is rejected at config load.
484
+ */
485
+ export declare const UsageConfigSchema: z.ZodObject<{
486
+ /** Master switch. When false, no usage is collected, persisted, or shown. */
487
+ enabled: z.ZodDefault<z.ZodBoolean>;
488
+ /** Currency label to prefix costs with (e.g. "$", "€"). Empty ⇒ no symbol is
489
+ * assumed — a bare number is shown, since the user configured the prices. */
490
+ currency: z.ZodDefault<z.ZodString>;
491
+ /** How many past runs to keep in the store; older ones are pruned oldest-first. */
492
+ retention: z.ZodDefault<z.ZodNumber>;
493
+ /** Per-tier prices. Any tier omitted is simply unpriced (cost omitted for it). */
494
+ prices: z.ZodDefault<z.ZodObject<{
495
+ kavi: z.ZodOptional<z.ZodObject<{
496
+ /** Price per 1,000,000 input tokens. */
497
+ input: z.ZodNumber;
498
+ /** Price per 1,000,000 output tokens. */
499
+ output: z.ZodNumber;
500
+ }, "strict", z.ZodTypeAny, {
501
+ input: number;
502
+ output: number;
503
+ }, {
504
+ input: number;
505
+ output: number;
506
+ }>>;
507
+ vaani: z.ZodOptional<z.ZodObject<{
508
+ /** Price per 1,000,000 input tokens. */
509
+ input: z.ZodNumber;
510
+ /** Price per 1,000,000 output tokens. */
511
+ output: z.ZodNumber;
512
+ }, "strict", z.ZodTypeAny, {
513
+ input: number;
514
+ output: number;
515
+ }, {
516
+ input: number;
517
+ output: number;
518
+ }>>;
519
+ mira: z.ZodOptional<z.ZodObject<{
520
+ /** Price per 1,000,000 input tokens. */
521
+ input: z.ZodNumber;
522
+ /** Price per 1,000,000 output tokens. */
523
+ output: z.ZodNumber;
524
+ }, "strict", z.ZodTypeAny, {
525
+ input: number;
526
+ output: number;
527
+ }, {
528
+ input: number;
529
+ output: number;
530
+ }>>;
531
+ }, "strict", z.ZodTypeAny, {
532
+ kavi?: {
533
+ input: number;
534
+ output: number;
535
+ } | undefined;
536
+ vaani?: {
537
+ input: number;
538
+ output: number;
539
+ } | undefined;
540
+ mira?: {
541
+ input: number;
542
+ output: number;
543
+ } | undefined;
544
+ }, {
545
+ kavi?: {
546
+ input: number;
547
+ output: number;
548
+ } | undefined;
549
+ vaani?: {
550
+ input: number;
551
+ output: number;
552
+ } | undefined;
553
+ mira?: {
554
+ input: number;
555
+ output: number;
556
+ } | undefined;
557
+ }>>;
558
+ }, "strict", z.ZodTypeAny, {
559
+ enabled: boolean;
560
+ retention: number;
561
+ currency: string;
562
+ prices: {
563
+ kavi?: {
564
+ input: number;
565
+ output: number;
566
+ } | undefined;
567
+ vaani?: {
568
+ input: number;
569
+ output: number;
570
+ } | undefined;
571
+ mira?: {
572
+ input: number;
573
+ output: number;
574
+ } | undefined;
575
+ };
576
+ }, {
577
+ enabled?: boolean | undefined;
578
+ retention?: number | undefined;
579
+ currency?: string | undefined;
580
+ prices?: {
581
+ kavi?: {
582
+ input: number;
583
+ output: number;
584
+ } | undefined;
585
+ vaani?: {
586
+ input: number;
587
+ output: number;
588
+ } | undefined;
589
+ mira?: {
590
+ input: number;
591
+ output: number;
592
+ } | undefined;
593
+ } | undefined;
594
+ }>;
595
+ export type UsageConfig = z.infer<typeof UsageConfigSchema>;
411
596
  /** MCP server entry — stdio or URL transport (wired up in a later phase). */
412
597
  export declare const McpServerSchema: z.ZodObject<{
413
598
  command: z.ZodOptional<z.ZodString>;
@@ -415,12 +600,12 @@ export declare const McpServerSchema: z.ZodObject<{
415
600
  url: z.ZodOptional<z.ZodString>;
416
601
  }, "strict", z.ZodTypeAny, {
417
602
  command?: string | undefined;
418
- args?: string[] | undefined;
419
603
  url?: string | undefined;
604
+ args?: string[] | undefined;
420
605
  }, {
421
606
  command?: string | undefined;
422
- args?: string[] | undefined;
423
607
  url?: string | undefined;
608
+ args?: string[] | undefined;
424
609
  }>;
425
610
  export declare const CruxyConfigSchema: z.ZodObject<{
426
611
  model: z.ZodDefault<z.ZodObject<{
@@ -610,6 +795,48 @@ export declare const CruxyConfigSchema: z.ZodObject<{
610
795
  overlapLines?: number | undefined;
611
796
  } | undefined;
612
797
  }>>;
798
+ lsp: z.ZodDefault<z.ZodObject<{
799
+ /** Master switch. When false, the four LSP tools are not registered and no
800
+ * server ever spawns (the feature stays fully inert). */
801
+ enabled: z.ZodDefault<z.ZodBoolean>;
802
+ /**
803
+ * Per-language command overrides, keyed by language id (e.g. `typescript`,
804
+ * `python`, `go`, `rust`). The value is the full command line
805
+ * (`"gopls -remote=auto"`); it is split on whitespace. Anything omitted
806
+ * falls back to the built-in default table (see `lsp/registry.ts`).
807
+ */
808
+ servers: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodString>>;
809
+ /** Kill and fail (CRUXY_E_LSP_TIMEOUT) if the `initialize` handshake does
810
+ * not complete within this many ms. */
811
+ startupTimeout: z.ZodDefault<z.ZodNumber>;
812
+ /** Fail a single query (CRUXY_E_LSP_TIMEOUT) if the server does not respond
813
+ * within this many ms — the server is kept alive, only the request errors. */
814
+ requestTimeout: z.ZodDefault<z.ZodNumber>;
815
+ /** Maximum concurrently-running language servers; acquiring past the cap
816
+ * evicts the idle-oldest server first. */
817
+ maxServers: z.ZodDefault<z.ZodNumber>;
818
+ /** Shut a server down after it has been idle this many ms. */
819
+ idleTimeout: z.ZodDefault<z.ZodNumber>;
820
+ /** Cap on locations/diagnostics returned by a single tool call; the rest are
821
+ * summarized as an "N more" note (bounded output). */
822
+ maxResults: z.ZodDefault<z.ZodNumber>;
823
+ }, "strict", z.ZodTypeAny, {
824
+ startupTimeout: number;
825
+ requestTimeout: number;
826
+ enabled: boolean;
827
+ servers: Record<string, string>;
828
+ maxServers: number;
829
+ idleTimeout: number;
830
+ maxResults: number;
831
+ }, {
832
+ startupTimeout?: number | undefined;
833
+ requestTimeout?: number | undefined;
834
+ enabled?: boolean | undefined;
835
+ servers?: Record<string, string> | undefined;
836
+ maxServers?: number | undefined;
837
+ idleTimeout?: number | undefined;
838
+ maxResults?: number | undefined;
839
+ }>>;
613
840
  checkpoint: z.ZodDefault<z.ZodObject<{
614
841
  /** Auto-checkpoint before a run's first mutation (and enable `cruxy rollback`). */
615
842
  enabled: z.ZodDefault<z.ZodBoolean>;
@@ -641,9 +868,9 @@ export declare const CruxyConfigSchema: z.ZodObject<{
641
868
  maxIterations: number;
642
869
  timeoutMs?: number | undefined;
643
870
  }, {
871
+ timeoutMs?: number | undefined;
644
872
  maxTokens?: number | undefined;
645
873
  maxIterations?: number | undefined;
646
- timeoutMs?: number | undefined;
647
874
  }>>;
648
875
  }, "strict", z.ZodTypeAny, {
649
876
  maxDepth: number;
@@ -655,9 +882,9 @@ export declare const CruxyConfigSchema: z.ZodObject<{
655
882
  }, {
656
883
  maxDepth?: number | undefined;
657
884
  defaultBudget?: {
885
+ timeoutMs?: number | undefined;
658
886
  maxTokens?: number | undefined;
659
887
  maxIterations?: number | undefined;
660
- timeoutMs?: number | undefined;
661
888
  } | undefined;
662
889
  }>>;
663
890
  test: z.ZodDefault<z.ZodObject<{
@@ -672,8 +899,8 @@ export declare const CruxyConfigSchema: z.ZodObject<{
672
899
  captureBytes: number;
673
900
  command?: string | undefined;
674
901
  }, {
675
- maxIterations?: number | undefined;
676
902
  command?: string | undefined;
903
+ maxIterations?: number | undefined;
677
904
  captureBytes?: number | undefined;
678
905
  }>>;
679
906
  sandbox: z.ZodDefault<z.ZodObject<{
@@ -767,18 +994,128 @@ export declare const CruxyConfigSchema: z.ZodObject<{
767
994
  enabled?: boolean | undefined;
768
995
  maxRecallTokens?: number | undefined;
769
996
  }>>;
997
+ usage: z.ZodDefault<z.ZodObject<{
998
+ /** Master switch. When false, no usage is collected, persisted, or shown. */
999
+ enabled: z.ZodDefault<z.ZodBoolean>;
1000
+ /** Currency label to prefix costs with (e.g. "$", "€"). Empty ⇒ no symbol is
1001
+ * assumed — a bare number is shown, since the user configured the prices. */
1002
+ currency: z.ZodDefault<z.ZodString>;
1003
+ /** How many past runs to keep in the store; older ones are pruned oldest-first. */
1004
+ retention: z.ZodDefault<z.ZodNumber>;
1005
+ /** Per-tier prices. Any tier omitted is simply unpriced (cost omitted for it). */
1006
+ prices: z.ZodDefault<z.ZodObject<{
1007
+ kavi: z.ZodOptional<z.ZodObject<{
1008
+ /** Price per 1,000,000 input tokens. */
1009
+ input: z.ZodNumber;
1010
+ /** Price per 1,000,000 output tokens. */
1011
+ output: z.ZodNumber;
1012
+ }, "strict", z.ZodTypeAny, {
1013
+ input: number;
1014
+ output: number;
1015
+ }, {
1016
+ input: number;
1017
+ output: number;
1018
+ }>>;
1019
+ vaani: z.ZodOptional<z.ZodObject<{
1020
+ /** Price per 1,000,000 input tokens. */
1021
+ input: z.ZodNumber;
1022
+ /** Price per 1,000,000 output tokens. */
1023
+ output: z.ZodNumber;
1024
+ }, "strict", z.ZodTypeAny, {
1025
+ input: number;
1026
+ output: number;
1027
+ }, {
1028
+ input: number;
1029
+ output: number;
1030
+ }>>;
1031
+ mira: z.ZodOptional<z.ZodObject<{
1032
+ /** Price per 1,000,000 input tokens. */
1033
+ input: z.ZodNumber;
1034
+ /** Price per 1,000,000 output tokens. */
1035
+ output: z.ZodNumber;
1036
+ }, "strict", z.ZodTypeAny, {
1037
+ input: number;
1038
+ output: number;
1039
+ }, {
1040
+ input: number;
1041
+ output: number;
1042
+ }>>;
1043
+ }, "strict", z.ZodTypeAny, {
1044
+ kavi?: {
1045
+ input: number;
1046
+ output: number;
1047
+ } | undefined;
1048
+ vaani?: {
1049
+ input: number;
1050
+ output: number;
1051
+ } | undefined;
1052
+ mira?: {
1053
+ input: number;
1054
+ output: number;
1055
+ } | undefined;
1056
+ }, {
1057
+ kavi?: {
1058
+ input: number;
1059
+ output: number;
1060
+ } | undefined;
1061
+ vaani?: {
1062
+ input: number;
1063
+ output: number;
1064
+ } | undefined;
1065
+ mira?: {
1066
+ input: number;
1067
+ output: number;
1068
+ } | undefined;
1069
+ }>>;
1070
+ }, "strict", z.ZodTypeAny, {
1071
+ enabled: boolean;
1072
+ retention: number;
1073
+ currency: string;
1074
+ prices: {
1075
+ kavi?: {
1076
+ input: number;
1077
+ output: number;
1078
+ } | undefined;
1079
+ vaani?: {
1080
+ input: number;
1081
+ output: number;
1082
+ } | undefined;
1083
+ mira?: {
1084
+ input: number;
1085
+ output: number;
1086
+ } | undefined;
1087
+ };
1088
+ }, {
1089
+ enabled?: boolean | undefined;
1090
+ retention?: number | undefined;
1091
+ currency?: string | undefined;
1092
+ prices?: {
1093
+ kavi?: {
1094
+ input: number;
1095
+ output: number;
1096
+ } | undefined;
1097
+ vaani?: {
1098
+ input: number;
1099
+ output: number;
1100
+ } | undefined;
1101
+ mira?: {
1102
+ input: number;
1103
+ output: number;
1104
+ } | undefined;
1105
+ } | undefined;
1106
+ }>>;
770
1107
  mcpServers: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodObject<{
771
1108
  command: z.ZodOptional<z.ZodString>;
772
1109
  args: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
773
1110
  url: z.ZodOptional<z.ZodString>;
774
1111
  }, "strict", z.ZodTypeAny, {
775
1112
  command?: string | undefined;
776
- args?: string[] | undefined;
777
1113
  url?: string | undefined;
1114
+ args?: string[] | undefined;
778
1115
  }, {
779
1116
  command?: string | undefined;
780
- args?: string[] | undefined;
781
1117
  url?: string | undefined;
1118
+ args?: string[] | undefined;
782
1119
  }>>>;
783
1120
  logLevel: z.ZodDefault<z.ZodEnum<["debug", "info", "warn", "error", "silent"]>>;
784
1121
  }, "strict", z.ZodTypeAny, {
@@ -789,6 +1126,25 @@ export declare const CruxyConfigSchema: z.ZodObject<{
789
1126
  enabled: boolean;
790
1127
  maxRecallTokens: number;
791
1128
  };
1129
+ usage: {
1130
+ enabled: boolean;
1131
+ retention: number;
1132
+ currency: string;
1133
+ prices: {
1134
+ kavi?: {
1135
+ input: number;
1136
+ output: number;
1137
+ } | undefined;
1138
+ vaani?: {
1139
+ input: number;
1140
+ output: number;
1141
+ } | undefined;
1142
+ mira?: {
1143
+ input: number;
1144
+ output: number;
1145
+ } | undefined;
1146
+ };
1147
+ };
792
1148
  checkpoint: {
793
1149
  enabled: boolean;
794
1150
  retention: number;
@@ -859,6 +1215,15 @@ export declare const CruxyConfigSchema: z.ZodObject<{
859
1215
  overlapLines: number;
860
1216
  };
861
1217
  };
1218
+ lsp: {
1219
+ startupTimeout: number;
1220
+ requestTimeout: number;
1221
+ enabled: boolean;
1222
+ servers: Record<string, string>;
1223
+ maxServers: number;
1224
+ idleTimeout: number;
1225
+ maxResults: number;
1226
+ };
862
1227
  test: {
863
1228
  maxIterations: number;
864
1229
  captureBytes: number;
@@ -874,8 +1239,8 @@ export declare const CruxyConfigSchema: z.ZodObject<{
874
1239
  };
875
1240
  mcpServers: Record<string, {
876
1241
  command?: string | undefined;
877
- args?: string[] | undefined;
878
1242
  url?: string | undefined;
1243
+ args?: string[] | undefined;
879
1244
  }>;
880
1245
  logLevel: "debug" | "info" | "warn" | "error" | "silent";
881
1246
  }, {
@@ -886,6 +1251,25 @@ export declare const CruxyConfigSchema: z.ZodObject<{
886
1251
  enabled?: boolean | undefined;
887
1252
  maxRecallTokens?: number | undefined;
888
1253
  } | undefined;
1254
+ usage?: {
1255
+ enabled?: boolean | undefined;
1256
+ retention?: number | undefined;
1257
+ currency?: string | undefined;
1258
+ prices?: {
1259
+ kavi?: {
1260
+ input: number;
1261
+ output: number;
1262
+ } | undefined;
1263
+ vaani?: {
1264
+ input: number;
1265
+ output: number;
1266
+ } | undefined;
1267
+ mira?: {
1268
+ input: number;
1269
+ output: number;
1270
+ } | undefined;
1271
+ } | undefined;
1272
+ } | undefined;
889
1273
  checkpoint?: {
890
1274
  enabled?: boolean | undefined;
891
1275
  retention?: number | undefined;
@@ -906,9 +1290,9 @@ export declare const CruxyConfigSchema: z.ZodObject<{
906
1290
  subagent?: {
907
1291
  maxDepth?: number | undefined;
908
1292
  defaultBudget?: {
1293
+ timeoutMs?: number | undefined;
909
1294
  maxTokens?: number | undefined;
910
1295
  maxIterations?: number | undefined;
911
- timeoutMs?: number | undefined;
912
1296
  } | undefined;
913
1297
  } | undefined;
914
1298
  model?: {
@@ -956,9 +1340,18 @@ export declare const CruxyConfigSchema: z.ZodObject<{
956
1340
  overlapLines?: number | undefined;
957
1341
  } | undefined;
958
1342
  } | undefined;
1343
+ lsp?: {
1344
+ startupTimeout?: number | undefined;
1345
+ requestTimeout?: number | undefined;
1346
+ enabled?: boolean | undefined;
1347
+ servers?: Record<string, string> | undefined;
1348
+ maxServers?: number | undefined;
1349
+ idleTimeout?: number | undefined;
1350
+ maxResults?: number | undefined;
1351
+ } | undefined;
959
1352
  test?: {
960
- maxIterations?: number | undefined;
961
1353
  command?: string | undefined;
1354
+ maxIterations?: number | undefined;
962
1355
  captureBytes?: number | undefined;
963
1356
  } | undefined;
964
1357
  hooks?: {
@@ -971,8 +1364,8 @@ export declare const CruxyConfigSchema: z.ZodObject<{
971
1364
  } | undefined;
972
1365
  mcpServers?: Record<string, {
973
1366
  command?: string | undefined;
974
- args?: string[] | undefined;
975
1367
  url?: string | undefined;
1368
+ args?: string[] | undefined;
976
1369
  }> | undefined;
977
1370
  logLevel?: "debug" | "info" | "warn" | "error" | "silent" | undefined;
978
1371
  }>;
@@ -290,6 +290,81 @@ export const MemoryConfigSchema = z
290
290
  maxRecallTokens: z.number().int().positive().default(1000),
291
291
  })
292
292
  .strict();
293
+ /**
294
+ * Per-language LSP integration (C.12): read-only, symbol-aware tools
295
+ * (find_definition, find_references, get_diagnostics, hover) backed by a
296
+ * managed pool of language servers. OFF by default — like the sandbox and
297
+ * hooks, it spawns and manages EXTERNAL server processes, a real execution
298
+ * surface the user opts into explicitly. When on, a missing server binary is
299
+ * an actionable, coded failure (CRUXY_E_LSP_SERVER_NOT_FOUND), never a silent
300
+ * empty result. Servers spawn lazily per language, are reused for the session,
301
+ * and are shut down cleanly (with a process-exit kill-tree backstop).
302
+ */
303
+ export const LspConfigSchema = z
304
+ .object({
305
+ /** Master switch. When false, the four LSP tools are not registered and no
306
+ * server ever spawns (the feature stays fully inert). */
307
+ enabled: z.boolean().default(false),
308
+ /**
309
+ * Per-language command overrides, keyed by language id (e.g. `typescript`,
310
+ * `python`, `go`, `rust`). The value is the full command line
311
+ * (`"gopls -remote=auto"`); it is split on whitespace. Anything omitted
312
+ * falls back to the built-in default table (see `lsp/registry.ts`).
313
+ */
314
+ servers: z.record(z.string(), z.string().min(1)).default({}),
315
+ /** Kill and fail (CRUXY_E_LSP_TIMEOUT) if the `initialize` handshake does
316
+ * not complete within this many ms. */
317
+ startupTimeout: z.number().int().positive().default(15000),
318
+ /** Fail a single query (CRUXY_E_LSP_TIMEOUT) if the server does not respond
319
+ * within this many ms — the server is kept alive, only the request errors. */
320
+ requestTimeout: z.number().int().positive().default(10000),
321
+ /** Maximum concurrently-running language servers; acquiring past the cap
322
+ * evicts the idle-oldest server first. */
323
+ maxServers: z.number().int().positive().default(4),
324
+ /** Shut a server down after it has been idle this many ms. */
325
+ idleTimeout: z.number().int().positive().default(300000),
326
+ /** Cap on locations/diagnostics returned by a single tool call; the rest are
327
+ * summarized as an "N more" note (bounded output). */
328
+ maxResults: z.number().int().positive().default(100),
329
+ })
330
+ .strict();
331
+ /** A per-tier price, in the user's own currency, PER MILLION TOKENS (C.22). */
332
+ export const TierPriceSchema = z
333
+ .object({
334
+ /** Price per 1,000,000 input tokens. */
335
+ input: z.number().nonnegative(),
336
+ /** Price per 1,000,000 output tokens. */
337
+ output: z.number().nonnegative(),
338
+ })
339
+ .strict();
340
+ /**
341
+ * Usage telemetry + cost tracking (C.22): LOCAL usage accounting only — nothing
342
+ * here is ever transmitted. Costs are opt-in and honest: prices are per-TIER and
343
+ * per-million-tokens, configured by the user; with none set, tokens are shown
344
+ * and cost is omitted (cruxy ships no bundled price table). The `prices` keys are
345
+ * the fixed {@link MODEL_TIERS}, so an upstream model name can never appear here
346
+ * (U.8 gag holds by construction) and a mistyped tier is rejected at config load.
347
+ */
348
+ export const UsageConfigSchema = z
349
+ .object({
350
+ /** Master switch. When false, no usage is collected, persisted, or shown. */
351
+ enabled: z.boolean().default(true),
352
+ /** Currency label to prefix costs with (e.g. "$", "€"). Empty ⇒ no symbol is
353
+ * assumed — a bare number is shown, since the user configured the prices. */
354
+ currency: z.string().default(""),
355
+ /** How many past runs to keep in the store; older ones are pruned oldest-first. */
356
+ retention: z.number().int().positive().default(50),
357
+ /** Per-tier prices. Any tier omitted is simply unpriced (cost omitted for it). */
358
+ prices: z
359
+ .object({
360
+ kavi: TierPriceSchema.optional(),
361
+ vaani: TierPriceSchema.optional(),
362
+ mira: TierPriceSchema.optional(),
363
+ })
364
+ .strict()
365
+ .default({}),
366
+ })
367
+ .strict();
293
368
  /** MCP server entry — stdio or URL transport (wired up in a later phase). */
294
369
  export const McpServerSchema = z
295
370
  .object({
@@ -309,6 +384,7 @@ export const CruxyConfigSchema = z
309
384
  context: ContextConfigSchema.default({}),
310
385
  approval: ApprovalConfigSchema.default({}),
311
386
  index: IndexConfigSchema.default({}),
387
+ lsp: LspConfigSchema.default({}),
312
388
  checkpoint: CheckpointConfigSchema.default({}),
313
389
  subagent: SubagentConfigSchema.default({}),
314
390
  test: TestConfigSchema.default({}),
@@ -316,6 +392,7 @@ export const CruxyConfigSchema = z
316
392
  hooks: HooksConfigSchema.default({}),
317
393
  routing: RoutingConfigSchema.default({}),
318
394
  memory: MemoryConfigSchema.default({}),
395
+ usage: UsageConfigSchema.default({}),
319
396
  mcpServers: z.record(z.string(), McpServerSchema).default({}),
320
397
  logLevel: z.enum(LOG_LEVELS).default("info"),
321
398
  })
@@ -41,6 +41,13 @@ export declare const MEMORY_FILE_NAME = "entries.json";
41
41
  * (`~/.cruxy/memory-trust.json`) — its own file, independent of hook trust, so
42
42
  * cloning a repo carries zero memory trust (C.29 supply-chain safety). */
43
43
  export declare const MEMORY_TRUST_FILE_NAME = "memory-trust.json";
44
+ /**
45
+ * Usage telemetry + cost tracking (C.22). Per-run/per-session usage records live
46
+ * in the GLOBAL dir only (`~/.cruxy/usage/runs.json`), `0600` — LOCAL accounting
47
+ * of your own usage, never transmitted. Pure data, validated, never eval'd.
48
+ */
49
+ export declare const USAGE_DIR_NAME = "usage";
50
+ export declare const USAGE_FILE_NAME = "runs.json";
44
51
  /**
45
52
  * Absolute path of the shipped builtin skills directory (`<pkg>/skills`).
46
53
  * Anchored the same way as the package.json lookup above: both `dist/` and
package/dist/constants.js CHANGED
@@ -61,6 +61,13 @@ export const MEMORY_FILE_NAME = "entries.json";
61
61
  * (`~/.cruxy/memory-trust.json`) — its own file, independent of hook trust, so
62
62
  * cloning a repo carries zero memory trust (C.29 supply-chain safety). */
63
63
  export const MEMORY_TRUST_FILE_NAME = "memory-trust.json";
64
+ /**
65
+ * Usage telemetry + cost tracking (C.22). Per-run/per-session usage records live
66
+ * in the GLOBAL dir only (`~/.cruxy/usage/runs.json`), `0600` — LOCAL accounting
67
+ * of your own usage, never transmitted. Pure data, validated, never eval'd.
68
+ */
69
+ export const USAGE_DIR_NAME = "usage";
70
+ export const USAGE_FILE_NAME = "runs.json";
64
71
  /**
65
72
  * Absolute path of the shipped builtin skills directory (`<pkg>/skills`).
66
73
  * Anchored the same way as the package.json lookup above: both `dist/` and