@corbat-tech/coco 2.33.2 → 2.35.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.
package/dist/index.js CHANGED
@@ -44,8 +44,13 @@ import yaml from 'highlight.js/lib/languages/yaml';
44
44
 
45
45
  var __defProp = Object.defineProperty;
46
46
  var __getOwnPropNames = Object.getOwnPropertyNames;
47
- var __esm = (fn, res) => function __init() {
48
- return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
47
+ var __esm = (fn, res, err) => function __init() {
48
+ if (err) throw err[0];
49
+ try {
50
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
51
+ } catch (e) {
52
+ throw err = [e], e;
53
+ }
49
54
  };
50
55
  var __export = (target, all) => {
51
56
  for (var name in all)
@@ -253,6 +258,793 @@ var init_logger = __esm({
253
258
  globalLogger = null;
254
259
  }
255
260
  });
261
+
262
+ // src/providers/catalog.ts
263
+ function model(entry) {
264
+ return {
265
+ ...entry,
266
+ source: entry.source ?? SOURCES.providerDocs
267
+ };
268
+ }
269
+ function getProviderCatalogEntry(provider) {
270
+ return PROVIDER_CATALOG[provider];
271
+ }
272
+ function getCatalogDefaultModel(provider) {
273
+ return getProviderCatalogEntry(provider).defaultModel;
274
+ }
275
+ function getCatalogModel(provider, modelId) {
276
+ return getProviderCatalogEntry(provider).models.find((modelEntry) => modelEntry.id === modelId);
277
+ }
278
+ function getCatalogContextWindow(provider, modelId, fallback) {
279
+ if (!modelId) return fallback;
280
+ const exact = getCatalogModel(provider, modelId);
281
+ if (exact) return exact.contextWindow;
282
+ return fallback;
283
+ }
284
+ function getCatalogModelPricingMap() {
285
+ const pricing = {};
286
+ for (const provider of Object.values(PROVIDER_CATALOG)) {
287
+ for (const modelEntry of provider.models) {
288
+ if (!modelEntry.pricing) continue;
289
+ pricing[modelEntry.id] = {
290
+ ...modelEntry.pricing,
291
+ contextWindow: modelEntry.contextWindow
292
+ };
293
+ }
294
+ }
295
+ return pricing;
296
+ }
297
+ var VERIFIED_AT, SOURCES, PROVIDER_CATALOG;
298
+ var init_catalog = __esm({
299
+ "src/providers/catalog.ts"() {
300
+ VERIFIED_AT = "2026-06-18";
301
+ SOURCES = {
302
+ openaiModels: {
303
+ name: "OpenAI models",
304
+ url: "https://developers.openai.com/api/docs/models",
305
+ verifiedAt: VERIFIED_AT
306
+ },
307
+ openaiAllModels: {
308
+ name: "OpenAI all models",
309
+ url: "https://developers.openai.com/api/docs/models/all",
310
+ verifiedAt: VERIFIED_AT
311
+ },
312
+ codexModels: {
313
+ name: "OpenAI Codex models",
314
+ url: "https://developers.openai.com/codex/models",
315
+ verifiedAt: VERIFIED_AT
316
+ },
317
+ anthropicModels: {
318
+ name: "Anthropic models overview",
319
+ url: "https://docs.anthropic.com/en/docs/about-claude/models/overview",
320
+ verifiedAt: VERIFIED_AT
321
+ },
322
+ anthropicDeprecations: {
323
+ name: "Anthropic model deprecations",
324
+ url: "https://docs.anthropic.com/en/docs/about-claude/model-deprecations",
325
+ verifiedAt: VERIFIED_AT
326
+ },
327
+ geminiModels: {
328
+ name: "Gemini API models",
329
+ url: "https://ai.google.dev/gemini-api/docs/models",
330
+ verifiedAt: VERIFIED_AT
331
+ },
332
+ geminiGuide: {
333
+ name: "Gemini 3 developer guide",
334
+ url: "https://ai.google.dev/gemini-api/docs/gemini-3",
335
+ verifiedAt: VERIFIED_AT
336
+ },
337
+ githubCopilotModels: {
338
+ name: "GitHub Copilot supported models",
339
+ url: "https://docs.github.com/copilot/reference/ai-models/supported-models",
340
+ verifiedAt: VERIFIED_AT
341
+ },
342
+ githubCopilotComparison: {
343
+ name: "GitHub Copilot model comparison",
344
+ url: "https://docs.github.com/en/copilot/reference/ai-models/model-comparison",
345
+ verifiedAt: VERIFIED_AT
346
+ },
347
+ moonshotDocs: {
348
+ name: "Moonshot AI docs",
349
+ url: "https://platform.moonshot.ai/docs",
350
+ verifiedAt: VERIFIED_AT
351
+ },
352
+ qwenDocs: {
353
+ name: "Alibaba Cloud Model Studio docs",
354
+ url: "https://www.alibabacloud.com/help/en/model-studio/",
355
+ verifiedAt: VERIFIED_AT
356
+ },
357
+ providerDocs: {
358
+ name: "Provider API documentation",
359
+ url: "https://github.com/corbat/corbat-coco/blob/main/docs/guides/PROVIDERS.md",
360
+ verifiedAt: VERIFIED_AT
361
+ }
362
+ };
363
+ PROVIDER_CATALOG = {
364
+ anthropic: {
365
+ id: "anthropic",
366
+ defaultModel: "claude-sonnet-4-6",
367
+ models: [
368
+ model({
369
+ id: "claude-opus-4-8",
370
+ name: "Claude Opus 4.8",
371
+ description: "Most capable Opus-tier model for complex agentic work",
372
+ contextWindow: 2e5,
373
+ maxOutputTokens: 128e3,
374
+ status: "current",
375
+ capabilities: [
376
+ "streaming",
377
+ "tool-use",
378
+ "vision",
379
+ "adaptive-thinking",
380
+ "reasoning-effort",
381
+ "anthropic-messages"
382
+ ],
383
+ source: SOURCES.anthropicModels
384
+ }),
385
+ model({
386
+ id: "claude-sonnet-4-6",
387
+ name: "Claude Sonnet 4.6",
388
+ description: "Balanced default for coding, tool use, and long-running tasks",
389
+ contextWindow: 2e5,
390
+ maxOutputTokens: 128e3,
391
+ recommended: true,
392
+ status: "current",
393
+ capabilities: [
394
+ "streaming",
395
+ "tool-use",
396
+ "vision",
397
+ "adaptive-thinking",
398
+ "reasoning-effort",
399
+ "anthropic-messages"
400
+ ],
401
+ pricing: { inputPerMillion: 3, outputPerMillion: 15 },
402
+ source: SOURCES.anthropicModels
403
+ }),
404
+ model({
405
+ id: "claude-opus-4-6",
406
+ name: "Claude Opus 4.6",
407
+ description: "Legacy Opus option; prefer Opus 4.8 for new configurations",
408
+ contextWindow: 2e5,
409
+ maxOutputTokens: 128e3,
410
+ status: "legacy",
411
+ capabilities: [
412
+ "streaming",
413
+ "tool-use",
414
+ "vision",
415
+ "adaptive-thinking",
416
+ "reasoning-effort",
417
+ "anthropic-messages"
418
+ ],
419
+ pricing: { inputPerMillion: 5, outputPerMillion: 25 },
420
+ source: SOURCES.anthropicModels
421
+ }),
422
+ model({
423
+ id: "claude-haiku-4-5-20251001",
424
+ name: "Claude Haiku 4.5",
425
+ description: "Fast low-cost Claude model",
426
+ contextWindow: 2e5,
427
+ maxOutputTokens: 64e3,
428
+ status: "current",
429
+ capabilities: ["streaming", "tool-use", "vision", "anthropic-messages"],
430
+ pricing: { inputPerMillion: 1, outputPerMillion: 5 },
431
+ source: SOURCES.anthropicModels
432
+ }),
433
+ model({
434
+ id: "claude-sonnet-4-20250514",
435
+ name: "Claude Sonnet 4",
436
+ description: "Retired on the Claude API; kept for config migration warnings",
437
+ contextWindow: 2e5,
438
+ maxOutputTokens: 64e3,
439
+ status: "deprecated",
440
+ capabilities: ["streaming", "tool-use", "vision", "thinking-budget", "anthropic-messages"],
441
+ pricing: { inputPerMillion: 3, outputPerMillion: 15 },
442
+ source: SOURCES.anthropicDeprecations
443
+ }),
444
+ model({
445
+ id: "claude-opus-4-20250514",
446
+ name: "Claude Opus 4",
447
+ description: "Retired on the Claude API; kept for config migration warnings",
448
+ contextWindow: 2e5,
449
+ maxOutputTokens: 64e3,
450
+ status: "deprecated",
451
+ capabilities: ["streaming", "tool-use", "vision", "thinking-budget", "anthropic-messages"],
452
+ pricing: { inputPerMillion: 15, outputPerMillion: 75 },
453
+ source: SOURCES.anthropicDeprecations
454
+ })
455
+ ]
456
+ },
457
+ openai: {
458
+ id: "openai",
459
+ defaultModel: "gpt-5.5",
460
+ models: [
461
+ model({
462
+ id: "gpt-5.5",
463
+ name: "GPT-5.5",
464
+ description: "Default for complex coding, agentic workflows, and tool-heavy tasks",
465
+ contextWindow: 1e6,
466
+ maxOutputTokens: 128e3,
467
+ recommended: true,
468
+ status: "current",
469
+ capabilities: ["streaming", "tool-use", "vision", "reasoning-effort", "openai-responses"],
470
+ pricing: { inputPerMillion: 5, outputPerMillion: 30 },
471
+ source: SOURCES.openaiModels
472
+ }),
473
+ model({
474
+ id: "gpt-5.4",
475
+ name: "GPT-5.4",
476
+ description: "Affordable model for coding and professional work",
477
+ contextWindow: 1e6,
478
+ maxOutputTokens: 128e3,
479
+ status: "current",
480
+ capabilities: ["streaming", "tool-use", "vision", "reasoning-effort", "openai-responses"],
481
+ source: SOURCES.openaiAllModels
482
+ }),
483
+ model({
484
+ id: "gpt-5.4-mini",
485
+ name: "GPT-5.4 mini",
486
+ description: "Fast model for lighter coding tasks and subagents",
487
+ contextWindow: 1e6,
488
+ maxOutputTokens: 128e3,
489
+ status: "current",
490
+ capabilities: ["streaming", "tool-use", "vision", "reasoning-effort", "openai-responses"],
491
+ source: SOURCES.openaiAllModels
492
+ }),
493
+ model({
494
+ id: "gpt-5.3-codex",
495
+ name: "GPT-5.3 Codex",
496
+ description: "Agentic coding model; keep separate from older ChatGPT-only aliases",
497
+ contextWindow: 4e5,
498
+ maxOutputTokens: 128e3,
499
+ status: "current",
500
+ capabilities: ["streaming", "tool-use", "reasoning-effort", "openai-responses"],
501
+ source: SOURCES.openaiAllModels
502
+ }),
503
+ model({
504
+ id: "gpt-5.2-codex",
505
+ name: "GPT-5.2 Codex",
506
+ description: "Deprecated Codex model retained for existing configs",
507
+ contextWindow: 4e5,
508
+ maxOutputTokens: 128e3,
509
+ status: "deprecated",
510
+ capabilities: ["streaming", "tool-use", "reasoning-effort", "openai-responses"],
511
+ source: SOURCES.openaiAllModels
512
+ }),
513
+ model({
514
+ id: "gpt-4.1",
515
+ name: "GPT-4.1",
516
+ description: "Legacy long-context non-reasoning model",
517
+ contextWindow: 1048576,
518
+ maxOutputTokens: 32768,
519
+ status: "legacy",
520
+ capabilities: ["streaming", "tool-use", "vision", "openai-chat"],
521
+ pricing: { inputPerMillion: 2, outputPerMillion: 8 },
522
+ source: SOURCES.openaiAllModels
523
+ })
524
+ ]
525
+ },
526
+ codex: {
527
+ id: "codex",
528
+ defaultModel: "gpt-5.5",
529
+ models: [
530
+ model({
531
+ id: "gpt-5.5",
532
+ name: "GPT-5.5",
533
+ description: "Recommended Codex model for complex coding work",
534
+ contextWindow: 1e6,
535
+ maxOutputTokens: 128e3,
536
+ recommended: true,
537
+ status: "current",
538
+ capabilities: ["streaming", "tool-use", "reasoning-effort", "openai-responses"],
539
+ source: SOURCES.codexModels
540
+ }),
541
+ model({
542
+ id: "gpt-5.4-mini",
543
+ name: "GPT-5.4 mini",
544
+ description: "Faster Codex option for lighter work and subagents",
545
+ contextWindow: 1e6,
546
+ maxOutputTokens: 128e3,
547
+ status: "current",
548
+ capabilities: ["streaming", "tool-use", "reasoning-effort", "openai-responses"],
549
+ source: SOURCES.codexModels
550
+ }),
551
+ model({
552
+ id: "gpt-5.3-codex-spark",
553
+ name: "GPT-5.3 Codex Spark",
554
+ description: "Research preview for near-instant coding iteration",
555
+ contextWindow: 4e5,
556
+ maxOutputTokens: 128e3,
557
+ status: "experimental",
558
+ capabilities: ["streaming", "tool-use", "reasoning-effort", "openai-responses"],
559
+ source: SOURCES.codexModels
560
+ }),
561
+ model({
562
+ id: "codex-mini-latest",
563
+ name: "Codex mini latest",
564
+ description: "Deprecated fast Codex CLI model retained for existing configs",
565
+ contextWindow: 128e3,
566
+ maxOutputTokens: 32e3,
567
+ status: "deprecated",
568
+ capabilities: ["streaming", "tool-use", "reasoning-effort", "openai-responses"],
569
+ source: SOURCES.openaiAllModels
570
+ })
571
+ ]
572
+ },
573
+ copilot: {
574
+ id: "copilot",
575
+ defaultModel: "claude-sonnet-4.6",
576
+ models: [
577
+ model({
578
+ id: "claude-sonnet-4.6",
579
+ name: "Claude Sonnet 4.6",
580
+ description: "Reliable Copilot default for coding and review",
581
+ contextWindow: 168e3,
582
+ maxOutputTokens: 64e3,
583
+ recommended: true,
584
+ status: "current",
585
+ capabilities: ["streaming", "tool-use", "vision", "openai-chat"],
586
+ source: SOURCES.githubCopilotComparison
587
+ }),
588
+ model({
589
+ id: "gpt-5.5",
590
+ name: "GPT-5.5",
591
+ description: "Copilot model for complex reasoning and technical decisions",
592
+ contextWindow: 1e6,
593
+ maxOutputTokens: 128e3,
594
+ status: "current",
595
+ capabilities: ["streaming", "tool-use", "vision", "openai-chat"],
596
+ source: SOURCES.githubCopilotComparison
597
+ }),
598
+ model({
599
+ id: "gpt-5.4",
600
+ name: "GPT-5.4",
601
+ description: "Copilot coding model",
602
+ contextWindow: 1e6,
603
+ maxOutputTokens: 128e3,
604
+ status: "current",
605
+ capabilities: ["streaming", "tool-use", "vision", "openai-chat"],
606
+ source: SOURCES.githubCopilotModels
607
+ }),
608
+ model({
609
+ id: "gpt-5.4-mini",
610
+ name: "GPT-5.4 mini",
611
+ description: "Fast Copilot model for interactive coding",
612
+ contextWindow: 1e6,
613
+ maxOutputTokens: 128e3,
614
+ status: "current",
615
+ capabilities: ["streaming", "tool-use", "vision", "openai-chat"],
616
+ source: SOURCES.githubCopilotModels
617
+ }),
618
+ model({
619
+ id: "gpt-5.3-codex",
620
+ name: "GPT-5.3 Codex",
621
+ description: "Copilot agentic coding model",
622
+ contextWindow: 4e5,
623
+ maxOutputTokens: 128e3,
624
+ status: "current",
625
+ capabilities: ["streaming", "tool-use", "openai-chat"],
626
+ source: SOURCES.githubCopilotModels
627
+ }),
628
+ model({
629
+ id: "claude-opus-4.8",
630
+ name: "Claude Opus 4.8",
631
+ description: "Most capable Anthropic model exposed by Copilot when available",
632
+ contextWindow: 168e3,
633
+ maxOutputTokens: 64e3,
634
+ status: "current",
635
+ capabilities: ["streaming", "tool-use", "vision", "openai-chat"],
636
+ source: SOURCES.githubCopilotModels
637
+ }),
638
+ model({
639
+ id: "gemini-3.1-pro",
640
+ name: "Gemini 3.1 Pro",
641
+ description: "Gemini model exposed by Copilot",
642
+ contextWindow: 1e6,
643
+ maxOutputTokens: 64e3,
644
+ status: "current",
645
+ capabilities: ["streaming", "tool-use", "vision", "openai-chat"],
646
+ source: SOURCES.githubCopilotModels
647
+ }),
648
+ model({
649
+ id: "gemini-3.5-flash",
650
+ name: "Gemini 3.5 Flash",
651
+ description: "Fast Gemini model exposed by Copilot",
652
+ contextWindow: 1e6,
653
+ maxOutputTokens: 64e3,
654
+ status: "current",
655
+ capabilities: ["streaming", "tool-use", "vision", "openai-chat"],
656
+ source: SOURCES.githubCopilotModels
657
+ })
658
+ ]
659
+ },
660
+ gemini: {
661
+ id: "gemini",
662
+ defaultModel: "gemini-3.1-pro-preview",
663
+ models: [
664
+ model({
665
+ id: "gemini-3.1-pro-preview",
666
+ name: "Gemini 3.1 Pro Preview",
667
+ description: "Most capable Gemini 3 model for agentic and coding workflows",
668
+ contextWindow: 1e6,
669
+ maxOutputTokens: 64e3,
670
+ recommended: true,
671
+ status: "experimental",
672
+ capabilities: [
673
+ "streaming",
674
+ "tool-use",
675
+ "vision",
676
+ "thinking-budget",
677
+ "gemini-generate-content"
678
+ ],
679
+ source: SOURCES.geminiGuide
680
+ }),
681
+ model({
682
+ id: "gemini-3-flash-preview",
683
+ name: "Gemini 3 Flash Preview",
684
+ description: "Fast Gemini 3 preview model",
685
+ contextWindow: 1e6,
686
+ maxOutputTokens: 64e3,
687
+ status: "experimental",
688
+ capabilities: [
689
+ "streaming",
690
+ "tool-use",
691
+ "vision",
692
+ "thinking-budget",
693
+ "gemini-generate-content"
694
+ ],
695
+ source: SOURCES.geminiGuide
696
+ }),
697
+ model({
698
+ id: "gemini-2.5-pro",
699
+ name: "Gemini 2.5 Pro",
700
+ description: "Stable Gemini Pro model",
701
+ contextWindow: 1048576,
702
+ maxOutputTokens: 65536,
703
+ status: "current",
704
+ capabilities: [
705
+ "streaming",
706
+ "tool-use",
707
+ "vision",
708
+ "thinking-budget",
709
+ "gemini-generate-content"
710
+ ],
711
+ source: SOURCES.geminiModels
712
+ }),
713
+ model({
714
+ id: "gemini-2.5-flash",
715
+ name: "Gemini 2.5 Flash",
716
+ description: "Stable fast Gemini model",
717
+ contextWindow: 1048576,
718
+ maxOutputTokens: 65536,
719
+ status: "current",
720
+ capabilities: [
721
+ "streaming",
722
+ "tool-use",
723
+ "vision",
724
+ "thinking-budget",
725
+ "gemini-generate-content"
726
+ ],
727
+ source: SOURCES.geminiModels
728
+ }),
729
+ model({
730
+ id: "gemini-2.5-flash-lite",
731
+ name: "Gemini 2.5 Flash-Lite",
732
+ description: "Lowest-cost stable Gemini option",
733
+ contextWindow: 1048576,
734
+ maxOutputTokens: 65536,
735
+ status: "current",
736
+ capabilities: [
737
+ "streaming",
738
+ "tool-use",
739
+ "vision",
740
+ "thinking-budget",
741
+ "gemini-generate-content"
742
+ ],
743
+ source: SOURCES.geminiModels
744
+ })
745
+ ]
746
+ },
747
+ vertex: {
748
+ id: "vertex",
749
+ defaultModel: "gemini-2.5-pro",
750
+ models: [
751
+ model({
752
+ id: "gemini-2.5-pro",
753
+ name: "Gemini 2.5 Pro",
754
+ description: "Stable Vertex model for coding and complex reasoning",
755
+ contextWindow: 1048576,
756
+ maxOutputTokens: 65536,
757
+ recommended: true,
758
+ status: "current",
759
+ capabilities: [
760
+ "streaming",
761
+ "tool-use",
762
+ "vision",
763
+ "thinking-budget",
764
+ "gemini-generate-content"
765
+ ],
766
+ source: SOURCES.geminiModels
767
+ }),
768
+ model({
769
+ id: "gemini-3-pro-preview",
770
+ name: "Gemini 3 Pro Preview",
771
+ description: "Preview Vertex Gemini 3 model",
772
+ contextWindow: 1048576,
773
+ maxOutputTokens: 65536,
774
+ status: "experimental",
775
+ capabilities: [
776
+ "streaming",
777
+ "tool-use",
778
+ "vision",
779
+ "thinking-budget",
780
+ "gemini-generate-content"
781
+ ],
782
+ source: SOURCES.geminiGuide
783
+ }),
784
+ model({
785
+ id: "gemini-3-flash-preview",
786
+ name: "Gemini 3 Flash Preview",
787
+ description: "Fast preview Vertex Gemini 3 model",
788
+ contextWindow: 1048576,
789
+ maxOutputTokens: 65536,
790
+ status: "experimental",
791
+ capabilities: [
792
+ "streaming",
793
+ "tool-use",
794
+ "vision",
795
+ "thinking-budget",
796
+ "gemini-generate-content"
797
+ ],
798
+ source: SOURCES.geminiGuide
799
+ }),
800
+ model({
801
+ id: "gemini-2.5-flash",
802
+ name: "Gemini 2.5 Flash",
803
+ description: "Fast stable Vertex Gemini model",
804
+ contextWindow: 1048576,
805
+ maxOutputTokens: 65536,
806
+ status: "current",
807
+ capabilities: [
808
+ "streaming",
809
+ "tool-use",
810
+ "vision",
811
+ "thinking-budget",
812
+ "gemini-generate-content"
813
+ ],
814
+ source: SOURCES.geminiModels
815
+ })
816
+ ]
817
+ },
818
+ kimi: {
819
+ id: "kimi",
820
+ defaultModel: "kimi-k2.5",
821
+ models: [
822
+ model({
823
+ id: "kimi-k2.5",
824
+ name: "Kimi K2.5",
825
+ description: "Moonshot model for coding and agentic work",
826
+ contextWindow: 262144,
827
+ maxOutputTokens: 32e3,
828
+ recommended: true,
829
+ status: "current",
830
+ capabilities: ["streaming", "tool-use", "openai-chat"],
831
+ source: SOURCES.moonshotDocs
832
+ }),
833
+ model({
834
+ id: "kimi-k2-thinking",
835
+ name: "Kimi K2 Thinking",
836
+ description: "Reasoning variant",
837
+ contextWindow: 262144,
838
+ maxOutputTokens: 32e3,
839
+ status: "current",
840
+ capabilities: ["streaming", "tool-use", "openai-chat"],
841
+ source: SOURCES.moonshotDocs
842
+ }),
843
+ model({
844
+ id: "moonshot-v1-128k",
845
+ name: "Moonshot v1 128K",
846
+ description: "Legacy long-context Moonshot model",
847
+ contextWindow: 131072,
848
+ maxOutputTokens: 8192,
849
+ status: "legacy",
850
+ capabilities: ["streaming", "tool-use", "openai-chat"],
851
+ pricing: { inputPerMillion: 6, outputPerMillion: 6 },
852
+ source: SOURCES.moonshotDocs
853
+ })
854
+ ]
855
+ },
856
+ "kimi-code": {
857
+ id: "kimi-code",
858
+ defaultModel: "kimi-for-coding",
859
+ models: [
860
+ model({
861
+ id: "kimi-for-coding",
862
+ name: "Kimi for Coding",
863
+ description: "Anthropic-compatible Kimi coding endpoint",
864
+ contextWindow: 131072,
865
+ maxOutputTokens: 32e3,
866
+ recommended: true,
867
+ status: "current",
868
+ capabilities: ["streaming", "tool-use", "anthropic-messages"],
869
+ source: SOURCES.moonshotDocs
870
+ })
871
+ ]
872
+ },
873
+ lmstudio: {
874
+ id: "lmstudio",
875
+ defaultModel: "local-model",
876
+ models: [
877
+ model({
878
+ id: "local-model",
879
+ name: "Local model",
880
+ description: "Model selected in LM Studio",
881
+ contextWindow: 32768,
882
+ maxOutputTokens: 8192,
883
+ recommended: true,
884
+ status: "current",
885
+ capabilities: ["streaming", "tool-use", "openai-chat"]
886
+ })
887
+ ]
888
+ },
889
+ ollama: {
890
+ id: "ollama",
891
+ defaultModel: "llama3.2",
892
+ models: [
893
+ model({
894
+ id: "llama3.2",
895
+ name: "Llama 3.2",
896
+ description: "Default local Ollama model",
897
+ contextWindow: 128e3,
898
+ maxOutputTokens: 8192,
899
+ recommended: true,
900
+ status: "current",
901
+ capabilities: ["streaming", "tool-use", "openai-chat"]
902
+ }),
903
+ model({
904
+ id: "qwen2.5-coder:14b",
905
+ name: "Qwen2.5 Coder 14B",
906
+ description: "Local coding model",
907
+ contextWindow: 32768,
908
+ maxOutputTokens: 8192,
909
+ status: "legacy",
910
+ capabilities: ["streaming", "tool-use", "openai-chat"]
911
+ })
912
+ ]
913
+ },
914
+ groq: {
915
+ id: "groq",
916
+ defaultModel: "llama-3.3-70b-versatile",
917
+ models: [
918
+ model({
919
+ id: "llama-3.3-70b-versatile",
920
+ name: "Llama 3.3 70B Versatile",
921
+ contextWindow: 128e3,
922
+ maxOutputTokens: 8192,
923
+ recommended: true,
924
+ status: "current",
925
+ capabilities: ["streaming", "tool-use", "openai-chat"]
926
+ })
927
+ ]
928
+ },
929
+ openrouter: {
930
+ id: "openrouter",
931
+ defaultModel: "anthropic/claude-sonnet-4.6",
932
+ models: [
933
+ model({
934
+ id: "anthropic/claude-sonnet-4.6",
935
+ name: "Claude Sonnet 4.6 via OpenRouter",
936
+ contextWindow: 2e5,
937
+ maxOutputTokens: 64e3,
938
+ recommended: true,
939
+ status: "current",
940
+ capabilities: ["streaming", "tool-use", "vision", "openai-chat"]
941
+ })
942
+ ]
943
+ },
944
+ mistral: {
945
+ id: "mistral",
946
+ defaultModel: "mistral-large-latest",
947
+ models: [
948
+ model({
949
+ id: "mistral-large-latest",
950
+ name: "Mistral Large latest",
951
+ contextWindow: 131072,
952
+ maxOutputTokens: 8192,
953
+ recommended: true,
954
+ status: "current",
955
+ capabilities: ["streaming", "tool-use", "openai-chat"]
956
+ }),
957
+ model({
958
+ id: "codestral-latest",
959
+ name: "Codestral latest",
960
+ contextWindow: 32768,
961
+ maxOutputTokens: 8192,
962
+ status: "current",
963
+ capabilities: ["streaming", "tool-use", "openai-chat"]
964
+ })
965
+ ]
966
+ },
967
+ deepseek: {
968
+ id: "deepseek",
969
+ defaultModel: "deepseek-chat",
970
+ models: [
971
+ model({
972
+ id: "deepseek-chat",
973
+ name: "DeepSeek Chat",
974
+ contextWindow: 65536,
975
+ maxOutputTokens: 8192,
976
+ recommended: true,
977
+ status: "current",
978
+ capabilities: ["streaming", "tool-use", "openai-chat"]
979
+ }),
980
+ model({
981
+ id: "deepseek-reasoner",
982
+ name: "DeepSeek Reasoner",
983
+ contextWindow: 65536,
984
+ maxOutputTokens: 8192,
985
+ status: "current",
986
+ capabilities: ["streaming", "tool-use", "openai-chat"]
987
+ })
988
+ ]
989
+ },
990
+ together: {
991
+ id: "together",
992
+ defaultModel: "meta-llama/Llama-3.3-70B-Instruct-Turbo",
993
+ models: [
994
+ model({
995
+ id: "meta-llama/Llama-3.3-70B-Instruct-Turbo",
996
+ name: "Llama 3.3 70B Instruct Turbo",
997
+ contextWindow: 128e3,
998
+ maxOutputTokens: 8192,
999
+ recommended: true,
1000
+ status: "current",
1001
+ capabilities: ["streaming", "tool-use", "openai-chat"]
1002
+ })
1003
+ ]
1004
+ },
1005
+ huggingface: {
1006
+ id: "huggingface",
1007
+ defaultModel: "meta-llama/Llama-3.1-70B-Instruct",
1008
+ models: [
1009
+ model({
1010
+ id: "meta-llama/Llama-3.1-70B-Instruct",
1011
+ name: "Llama 3.1 70B Instruct",
1012
+ contextWindow: 128e3,
1013
+ maxOutputTokens: 8192,
1014
+ recommended: true,
1015
+ status: "legacy",
1016
+ capabilities: ["streaming", "openai-chat"]
1017
+ })
1018
+ ]
1019
+ },
1020
+ qwen: {
1021
+ id: "qwen",
1022
+ defaultModel: "qwen-coder-plus",
1023
+ models: [
1024
+ model({
1025
+ id: "qwen-coder-plus",
1026
+ name: "Qwen Coder Plus",
1027
+ contextWindow: 131072,
1028
+ maxOutputTokens: 8192,
1029
+ recommended: true,
1030
+ status: "current",
1031
+ capabilities: ["streaming", "tool-use", "openai-chat"],
1032
+ source: SOURCES.qwenDocs
1033
+ }),
1034
+ model({
1035
+ id: "qwen-max",
1036
+ name: "Qwen Max",
1037
+ contextWindow: 131072,
1038
+ maxOutputTokens: 8192,
1039
+ status: "current",
1040
+ capabilities: ["streaming", "tool-use", "openai-chat"],
1041
+ source: SOURCES.qwenDocs
1042
+ })
1043
+ ]
1044
+ }
1045
+ };
1046
+ }
1047
+ });
256
1048
  async function refreshAccessToken(provider, refreshToken) {
257
1049
  const config = OAUTH_CONFIGS[provider];
258
1050
  if (!config) {
@@ -858,6 +1650,22 @@ function isCopilotTokenExpired(creds) {
858
1650
  if (!creds.copilotToken || !creds.copilotTokenExpiresAt) return true;
859
1651
  return Date.now() >= creds.copilotTokenExpiresAt - REFRESH_BUFFER_MS;
860
1652
  }
1653
+ function exchangeForCopilotTokenViaGhCli() {
1654
+ return new Promise((resolve3) => {
1655
+ execFile("gh", ["api", "/copilot_internal/v2/token"], { timeout: 1e4 }, (err, stdout) => {
1656
+ if (err || !stdout) {
1657
+ resolve3(null);
1658
+ return;
1659
+ }
1660
+ try {
1661
+ const parsed = JSON.parse(stdout);
1662
+ resolve3(parsed.token && parsed.expires_at ? parsed : null);
1663
+ } catch {
1664
+ resolve3(null);
1665
+ }
1666
+ });
1667
+ });
1668
+ }
861
1669
  async function getValidCopilotToken() {
862
1670
  const creds = await loadCopilotCredentials();
863
1671
  const envToken = process.env["COPILOT_GITHUB_TOKEN"] || process.env["GH_TOKEN"] || process.env["GITHUB_TOKEN"];
@@ -871,8 +1679,7 @@ async function getValidCopilotToken() {
871
1679
  isNew: false
872
1680
  };
873
1681
  }
874
- try {
875
- const copilotToken = await exchangeForCopilotToken(githubToken);
1682
+ const saveAndReturn = async (copilotToken) => {
876
1683
  const updatedCreds = {
877
1684
  ...creds ?? { githubToken },
878
1685
  githubToken: creds?.githubToken ?? githubToken,
@@ -886,11 +1693,23 @@ async function getValidCopilotToken() {
886
1693
  baseUrl: getCopilotBaseUrl(updatedCreds.accountType),
887
1694
  isNew: true
888
1695
  };
1696
+ };
1697
+ try {
1698
+ const copilotToken = await exchangeForCopilotToken(githubToken);
1699
+ return saveAndReturn(copilotToken);
889
1700
  } catch (error) {
890
1701
  if (error instanceof CopilotAuthError && error.permanent) {
1702
+ const ghCliToken2 = await exchangeForCopilotTokenViaGhCli();
1703
+ if (ghCliToken2) {
1704
+ return saveAndReturn(ghCliToken2);
1705
+ }
891
1706
  await deleteCopilotCredentials();
892
1707
  return null;
893
1708
  }
1709
+ const ghCliToken = await exchangeForCopilotTokenViaGhCli();
1710
+ if (ghCliToken) {
1711
+ return saveAndReturn(ghCliToken);
1712
+ }
894
1713
  throw error;
895
1714
  }
896
1715
  }
@@ -912,6 +1731,7 @@ var init_copilot = __esm({
912
1731
  this.permanent = permanent;
913
1732
  this.name = "CopilotAuthError";
914
1733
  }
1734
+ permanent;
915
1735
  };
916
1736
  CopilotCredentialsSchema = z.object({
917
1737
  githubToken: z.string().min(1),
@@ -1487,8 +2307,8 @@ async function configExists(configPath, scope = "any") {
1487
2307
  }
1488
2308
  return false;
1489
2309
  }
1490
- function getConfigValue(config, path42) {
1491
- const keys = path42.split(".");
2310
+ function getConfigValue(config, path44) {
2311
+ const keys = path44.split(".");
1492
2312
  let current = config;
1493
2313
  for (const key of keys) {
1494
2314
  if (current === null || current === void 0 || typeof current !== "object") {
@@ -1636,41 +2456,41 @@ function getBaseUrl(provider) {
1636
2456
  function getDefaultModel(provider) {
1637
2457
  switch (provider) {
1638
2458
  case "anthropic":
1639
- return process.env["ANTHROPIC_MODEL"] ?? "claude-opus-4-6";
2459
+ return process.env["ANTHROPIC_MODEL"] ?? getCatalogDefaultModel(provider);
1640
2460
  case "openai":
1641
- return process.env["OPENAI_MODEL"] ?? "gpt-5.3-codex";
2461
+ return process.env["OPENAI_MODEL"] ?? getCatalogDefaultModel(provider);
1642
2462
  case "gemini":
1643
- return process.env["GEMINI_MODEL"] ?? "gemini-3.1-pro-preview";
2463
+ return process.env["GEMINI_MODEL"] ?? getCatalogDefaultModel(provider);
1644
2464
  case "vertex":
1645
- return process.env["VERTEX_MODEL"] ?? "gemini-2.5-pro";
2465
+ return process.env["VERTEX_MODEL"] ?? getCatalogDefaultModel(provider);
1646
2466
  case "kimi":
1647
- return process.env["KIMI_MODEL"] ?? "kimi-k2.5";
2467
+ return process.env["KIMI_MODEL"] ?? getCatalogDefaultModel(provider);
1648
2468
  case "kimi-code":
1649
- return process.env["KIMI_CODE_MODEL"] ?? "kimi-for-coding";
2469
+ return process.env["KIMI_CODE_MODEL"] ?? getCatalogDefaultModel(provider);
1650
2470
  case "lmstudio":
1651
- return process.env["LMSTUDIO_MODEL"] ?? "local-model";
2471
+ return process.env["LMSTUDIO_MODEL"] ?? getCatalogDefaultModel(provider);
1652
2472
  case "ollama":
1653
- return process.env["OLLAMA_MODEL"] ?? "llama3.2";
2473
+ return process.env["OLLAMA_MODEL"] ?? getCatalogDefaultModel(provider);
1654
2474
  case "codex":
1655
- return process.env["CODEX_MODEL"] ?? "codex-mini-latest";
2475
+ return process.env["CODEX_MODEL"] ?? getCatalogDefaultModel(provider);
1656
2476
  case "copilot":
1657
- return process.env["COPILOT_MODEL"] ?? "claude-sonnet-4.6";
2477
+ return process.env["COPILOT_MODEL"] ?? getCatalogDefaultModel(provider);
1658
2478
  case "groq":
1659
- return process.env["GROQ_MODEL"] ?? "llama-3.3-70b-versatile";
2479
+ return process.env["GROQ_MODEL"] ?? getCatalogDefaultModel(provider);
1660
2480
  case "openrouter":
1661
- return process.env["OPENROUTER_MODEL"] ?? "anthropic/claude-3.5-sonnet";
2481
+ return process.env["OPENROUTER_MODEL"] ?? getCatalogDefaultModel(provider);
1662
2482
  case "mistral":
1663
- return process.env["MISTRAL_MODEL"] ?? "mistral-large-latest";
2483
+ return process.env["MISTRAL_MODEL"] ?? getCatalogDefaultModel(provider);
1664
2484
  case "deepseek":
1665
- return process.env["DEEPSEEK_MODEL"] ?? "deepseek-chat";
2485
+ return process.env["DEEPSEEK_MODEL"] ?? getCatalogDefaultModel(provider);
1666
2486
  case "together":
1667
- return process.env["TOGETHER_MODEL"] ?? "meta-llama/Llama-3.3-70B-Instruct-Turbo";
2487
+ return process.env["TOGETHER_MODEL"] ?? getCatalogDefaultModel(provider);
1668
2488
  case "huggingface":
1669
- return process.env["HF_MODEL"] ?? "meta-llama/Llama-3.1-70B-Instruct";
2489
+ return process.env["HF_MODEL"] ?? getCatalogDefaultModel(provider);
1670
2490
  case "qwen":
1671
- return process.env["QWEN_MODEL"] ?? "qwen-max";
2491
+ return process.env["QWEN_MODEL"] ?? getCatalogDefaultModel(provider);
1672
2492
  default:
1673
- return "claude-sonnet-4-6";
2493
+ return getCatalogDefaultModel("anthropic");
1674
2494
  }
1675
2495
  }
1676
2496
  function getDefaultProvider() {
@@ -1680,11 +2500,24 @@ function getDefaultProvider() {
1680
2500
  }
1681
2501
  return "anthropic";
1682
2502
  }
2503
+ function getEditorModel() {
2504
+ const raw = process.env["COCO_EDITOR_MODEL"]?.trim();
2505
+ if (!raw || raw.length === 0) return void 0;
2506
+ if (["none", "default", "null", "undefined"].includes(raw.toLowerCase())) return void 0;
2507
+ return raw;
2508
+ }
2509
+ function getWeakModel() {
2510
+ const raw = process.env["COCO_WEAK_MODEL"]?.trim();
2511
+ if (!raw || raw.length === 0) return void 0;
2512
+ if (["none", "default", "null", "undefined"].includes(raw.toLowerCase())) return void 0;
2513
+ return raw;
2514
+ }
1683
2515
  var VALID_PROVIDERS;
1684
2516
  var init_env = __esm({
1685
2517
  "src/config/env.ts"() {
1686
2518
  init_loader();
1687
2519
  init_paths();
2520
+ init_catalog();
1688
2521
  loadGlobalCocoEnv();
1689
2522
  VALID_PROVIDERS = [
1690
2523
  "anthropic",
@@ -1709,7 +2542,9 @@ var init_env = __esm({
1709
2542
  provider: getDefaultProvider(),
1710
2543
  getApiKey,
1711
2544
  getBaseUrl,
1712
- getDefaultModel
2545
+ getDefaultModel,
2546
+ getWeakModel,
2547
+ getEditorModel
1713
2548
  });
1714
2549
  }
1715
2550
  });
@@ -2019,9 +2854,9 @@ async function migrateGlobalConfig(oldDir, newConfigPath) {
2019
2854
  );
2020
2855
  }
2021
2856
  }
2022
- async function fileExists3(path42) {
2857
+ async function fileExists3(path44) {
2023
2858
  try {
2024
- await access(path42);
2859
+ await access(path44);
2025
2860
  return true;
2026
2861
  } catch {
2027
2862
  return false;
@@ -3054,10 +3889,10 @@ function inferTargetUsers(session) {
3054
3889
  /(?:for|by)\s+(developers?|users?|administrators?|customers?)/gi,
3055
3890
  /(developers?|users?|administrators?|customers?)\s+(?:can|will|should)/gi
3056
3891
  ];
3057
- const text = session.requirements.map((r) => r.description).join(" ");
3892
+ const text2 = session.requirements.map((r) => r.description).join(" ");
3058
3893
  for (const pattern of userPatterns) {
3059
3894
  let match;
3060
- while ((match = pattern.exec(text)) !== null) {
3895
+ while ((match = pattern.exec(text2)) !== null) {
3061
3896
  const user = match[1]?.toLowerCase();
3062
3897
  if (user && !users.includes(user)) {
3063
3898
  users.push(user);
@@ -3070,13 +3905,13 @@ function inferTargetUsers(session) {
3070
3905
  return users;
3071
3906
  }
3072
3907
  function inferProjectType(session) {
3073
- const text = session.initialInput.toLowerCase();
3074
- if (text.includes("cli") || text.includes("command line")) return "cli";
3075
- if (text.includes("api") || text.includes("rest") || text.includes("graphql")) return "api";
3076
- if (text.includes("web app") || text.includes("frontend")) return "web_app";
3077
- if (text.includes("library") || text.includes("package")) return "library";
3078
- if (text.includes("service") || text.includes("daemon")) return "service";
3079
- if (text.includes("full stack") || text.includes("fullstack")) return "full_stack";
3908
+ const text2 = session.initialInput.toLowerCase();
3909
+ if (text2.includes("cli") || text2.includes("command line")) return "cli";
3910
+ if (text2.includes("api") || text2.includes("rest") || text2.includes("graphql")) return "api";
3911
+ if (text2.includes("web app") || text2.includes("frontend")) return "web_app";
3912
+ if (text2.includes("library") || text2.includes("package")) return "library";
3913
+ if (text2.includes("service") || text2.includes("daemon")) return "service";
3914
+ if (text2.includes("full stack") || text2.includes("fullstack")) return "full_stack";
3080
3915
  return "unknown";
3081
3916
  }
3082
3917
  function assessComplexity(session) {
@@ -4622,14 +5457,14 @@ function generateArchitectureMarkdown(doc) {
4622
5457
  if (doc.dataModels.length > 0) {
4623
5458
  sections.push("## Data Models");
4624
5459
  sections.push("");
4625
- for (const model of doc.dataModels) {
4626
- sections.push(`### ${model.name}`);
5460
+ for (const model2 of doc.dataModels) {
5461
+ sections.push(`### ${model2.name}`);
4627
5462
  sections.push("");
4628
- sections.push(model.description);
5463
+ sections.push(model2.description);
4629
5464
  sections.push("");
4630
5465
  sections.push("| Field | Type | Required |");
4631
5466
  sections.push("|-------|------|----------|");
4632
- for (const field of model.fields) {
5467
+ for (const field of model2.fields) {
4633
5468
  sections.push(`| ${field.name} | ${field.type} | ${field.required ? "Yes" : "No"} |`);
4634
5469
  }
4635
5470
  sections.push("");
@@ -5853,6 +6688,7 @@ var CoverageAnalyzer = class {
5853
6688
  constructor(projectPath) {
5854
6689
  this.projectPath = projectPath;
5855
6690
  }
6691
+ projectPath;
5856
6692
  /**
5857
6693
  * Analyze coverage by running tests with coverage enabled
5858
6694
  */
@@ -6195,6 +7031,7 @@ var SnykSecurityScanner = class {
6195
7031
  constructor(projectPath) {
6196
7032
  this.projectPath = projectPath;
6197
7033
  }
7034
+ projectPath;
6198
7035
  /**
6199
7036
  * Scan project with Snyk (requires authentication)
6200
7037
  */
@@ -6406,6 +7243,8 @@ var ComplexityAnalyzer = class {
6406
7243
  this.projectPath = projectPath;
6407
7244
  this.threshold = threshold;
6408
7245
  }
7246
+ projectPath;
7247
+ threshold;
6409
7248
  /**
6410
7249
  * Analyze complexity of project files
6411
7250
  */
@@ -6491,6 +7330,8 @@ var DuplicationAnalyzer = class {
6491
7330
  this.projectPath = projectPath;
6492
7331
  this.minLines = minLines;
6493
7332
  }
7333
+ projectPath;
7334
+ minLines;
6494
7335
  /**
6495
7336
  * Detect code duplication
6496
7337
  */
@@ -6859,6 +7700,7 @@ var CorrectnessAnalyzer = class {
6859
7700
  this.projectPath = projectPath;
6860
7701
  this.buildVerifier = new BuildVerifier(projectPath);
6861
7702
  }
7703
+ projectPath;
6862
7704
  buildVerifier;
6863
7705
  /**
6864
7706
  * Analyze correctness by running tests and verifying build
@@ -6991,6 +7833,7 @@ var CompletenessAnalyzer = class {
6991
7833
  constructor(projectPath) {
6992
7834
  this.projectPath = projectPath;
6993
7835
  }
7836
+ projectPath;
6994
7837
  /**
6995
7838
  * Analyze project completeness
6996
7839
  */
@@ -7224,6 +8067,7 @@ var RobustnessAnalyzer = class {
7224
8067
  constructor(projectPath) {
7225
8068
  this.projectPath = projectPath;
7226
8069
  }
8070
+ projectPath;
7227
8071
  /**
7228
8072
  * Analyze robustness of project files
7229
8073
  */
@@ -7381,6 +8225,7 @@ var TestQualityAnalyzer = class {
7381
8225
  constructor(projectPath) {
7382
8226
  this.projectPath = projectPath;
7383
8227
  }
8228
+ projectPath;
7384
8229
  /**
7385
8230
  * Analyze test quality across the project
7386
8231
  */
@@ -7510,6 +8355,7 @@ var DocumentationAnalyzer = class {
7510
8355
  constructor(projectPath) {
7511
8356
  this.projectPath = projectPath;
7512
8357
  }
8358
+ projectPath;
7513
8359
  /**
7514
8360
  * Analyze documentation quality
7515
8361
  */
@@ -7664,6 +8510,7 @@ var StyleAnalyzer = class {
7664
8510
  constructor(projectPath) {
7665
8511
  this.projectPath = projectPath;
7666
8512
  }
8513
+ projectPath;
7667
8514
  /**
7668
8515
  * Analyze style/linting quality
7669
8516
  */
@@ -7873,6 +8720,7 @@ var ReadabilityAnalyzer = class {
7873
8720
  constructor(projectPath) {
7874
8721
  this.projectPath = projectPath;
7875
8722
  }
8723
+ projectPath;
7876
8724
  /**
7877
8725
  * Analyze readability of project files
7878
8726
  */
@@ -8010,6 +8858,7 @@ var MaintainabilityAnalyzer = class {
8010
8858
  constructor(projectPath) {
8011
8859
  this.projectPath = projectPath;
8012
8860
  }
8861
+ projectPath;
8013
8862
  /**
8014
8863
  * Analyze maintainability of project files
8015
8864
  */
@@ -8377,6 +9226,7 @@ var JavaComplexityAnalyzer = class {
8377
9226
  constructor(projectPath) {
8378
9227
  this.projectPath = projectPath;
8379
9228
  }
9229
+ projectPath;
8380
9230
  async analyze(files) {
8381
9231
  const javaFiles = files ?? await findJavaFiles(this.projectPath);
8382
9232
  if (!javaFiles.length) {
@@ -8516,6 +9366,7 @@ var JavaSecurityAnalyzer = class {
8516
9366
  constructor(projectPath) {
8517
9367
  this.projectPath = projectPath;
8518
9368
  }
9369
+ projectPath;
8519
9370
  async analyze(files) {
8520
9371
  const javaFiles = files ?? await findJavaFiles(this.projectPath, { includeTests: false });
8521
9372
  if (!javaFiles.length) {
@@ -8580,6 +9431,7 @@ var JavaStyleAnalyzer = class {
8580
9431
  constructor(projectPath) {
8581
9432
  this.projectPath = projectPath;
8582
9433
  }
9434
+ projectPath;
8583
9435
  async analyze(files) {
8584
9436
  const javaFiles = files ?? await findJavaFiles(this.projectPath);
8585
9437
  if (!javaFiles.length) return { score: 100, violations: [] };
@@ -8678,6 +9530,7 @@ var JavaDocumentationAnalyzer = class {
8678
9530
  constructor(projectPath) {
8679
9531
  this.projectPath = projectPath;
8680
9532
  }
9533
+ projectPath;
8681
9534
  async analyze(files) {
8682
9535
  const javaFiles = files ?? await findJavaFiles(this.projectPath, { srcPattern: "src/main/**/*.java" });
8683
9536
  if (!javaFiles.length) {
@@ -8755,6 +9608,7 @@ var JavaCoverageAnalyzer = class {
8755
9608
  constructor(projectPath) {
8756
9609
  this.projectPath = projectPath;
8757
9610
  }
9611
+ projectPath;
8758
9612
  async analyze() {
8759
9613
  for (const reportPath of JACOCO_REPORT_PATHS) {
8760
9614
  try {
@@ -8886,6 +9740,7 @@ var ReactComponentAnalyzer = class {
8886
9740
  constructor(projectPath) {
8887
9741
  this.projectPath = projectPath;
8888
9742
  }
9743
+ projectPath;
8889
9744
  async analyze(files) {
8890
9745
  const reactFiles = files ?? await findReactFiles(this.projectPath);
8891
9746
  if (!reactFiles.length) return { score: 100, totalComponents: 0, issues: [] };
@@ -8985,6 +9840,7 @@ var ReactA11yAnalyzer = class {
8985
9840
  constructor(projectPath) {
8986
9841
  this.projectPath = projectPath;
8987
9842
  }
9843
+ projectPath;
8988
9844
  async analyze(files) {
8989
9845
  const reactFiles = files ?? await findReactFiles(this.projectPath);
8990
9846
  if (!reactFiles.length) return { score: 100, violations: [] };
@@ -9077,6 +9933,7 @@ var ReactHookAnalyzer = class {
9077
9933
  constructor(projectPath) {
9078
9934
  this.projectPath = projectPath;
9079
9935
  }
9936
+ projectPath;
9080
9937
  async analyze(files) {
9081
9938
  const reactFiles = files ?? await findReactFiles(this.projectPath, "**/*.{tsx,jsx,ts,js}");
9082
9939
  if (!reactFiles.length) return { score: 100, violations: [] };
@@ -9490,6 +10347,8 @@ var QualityEvaluator = class {
9490
10347
  this.readabilityAnalyzer = new ReadabilityAnalyzer(projectPath);
9491
10348
  this.maintainabilityAnalyzer = new MaintainabilityAnalyzer(projectPath);
9492
10349
  }
10350
+ projectPath;
10351
+ registry;
9493
10352
  coverageAnalyzer;
9494
10353
  securityScanner;
9495
10354
  complexityAnalyzer;
@@ -10107,12 +10966,12 @@ function humanizeError(message, toolName) {
10107
10966
  return msg;
10108
10967
  }
10109
10968
  if (/ENOENT/i.test(msg)) {
10110
- const path42 = extractQuotedPath(msg);
10111
- return path42 ? `File or directory not found: ${path42}` : "File or directory not found";
10969
+ const path44 = extractQuotedPath(msg);
10970
+ return path44 ? `File or directory not found: ${path44}` : "File or directory not found";
10112
10971
  }
10113
10972
  if (/EACCES/i.test(msg)) {
10114
- const path42 = extractQuotedPath(msg);
10115
- return path42 ? `Permission denied: ${path42}` : "Permission denied \u2014 check file permissions";
10973
+ const path44 = extractQuotedPath(msg);
10974
+ return path44 ? `Permission denied: ${path44}` : "Permission denied \u2014 check file permissions";
10116
10975
  }
10117
10976
  if (/EISDIR/i.test(msg)) {
10118
10977
  return "Expected a file but found a directory at the specified path";
@@ -10316,13 +11175,21 @@ var ToolRegistry = class {
10316
11175
  const field = issue.path.join(".") || "input";
10317
11176
  return `${field} (${issue.message.toLowerCase()})`;
10318
11177
  });
10319
- errorMessage = `Invalid tool input \u2014 ${fields.join(", ")}`;
11178
+ errorMessage = `Invalid tool input for '${name}' \u2014 ${fields.join(", ")}`;
10320
11179
  const allUndefined = error.issues.every(
10321
11180
  (i) => i.message.toLowerCase().includes("received undefined")
10322
11181
  );
10323
11182
  if (allUndefined && error.issues.length > 1) {
10324
11183
  errorMessage += ". All parameters are missing \u2014 this is likely a JSON serialization error on our side. Please retry with the same arguments.";
10325
11184
  }
11185
+ try {
11186
+ const schema = zodToJsonSchema(tool.parameters);
11187
+ errorMessage += `
11188
+
11189
+ Expected schema for '${name}':
11190
+ ${JSON.stringify(schema, null, 2)}`;
11191
+ } catch {
11192
+ }
10326
11193
  } else if (isCocoError(error)) {
10327
11194
  const causeMsg = error.cause instanceof Error ? error.cause.message : "";
10328
11195
  const isRawEnoent = causeMsg.startsWith("ENOENT:");
@@ -11512,8 +12379,8 @@ function createLLMAdapter2(context) {
11512
12379
  type: "done"
11513
12380
  };
11514
12381
  },
11515
- countTokens(text) {
11516
- return Math.ceil(text.length / 4);
12382
+ countTokens(text2) {
12383
+ return Math.ceil(text2.length / 4);
11517
12384
  },
11518
12385
  getContextWindow() {
11519
12386
  return 2e5;
@@ -13581,30 +14448,110 @@ var GEMINI_BUDGET = {
13581
14448
  medium: 8e3,
13582
14449
  high: 16e3
13583
14450
  };
13584
- function isAnthropicThinkingModel(model) {
13585
- const m = model.toLowerCase();
14451
+ function isAnthropicThinkingModel(model2) {
14452
+ const m = model2.toLowerCase();
13586
14453
  if (m === "kimi-for-coding") return false;
13587
14454
  return m.includes("claude-3-7") || m.includes("claude-opus-4") || m.includes("claude-sonnet-4") || m.includes("claude-haiku-4-5") || m.includes("claude-4");
13588
14455
  }
13589
- function isOpenAIReasoningModel(model) {
13590
- const m = model.toLowerCase();
14456
+ function isAnthropicAdaptiveThinkingModel(model2) {
14457
+ const m = model2.toLowerCase();
14458
+ return m.includes("claude-opus-4-8") || m.includes("claude-opus-4-7") || m.includes("claude-opus-4-6") || m.includes("claude-sonnet-4-6");
14459
+ }
14460
+ function isOpenAIReasoningModel(model2) {
14461
+ const m = model2.toLowerCase();
13591
14462
  return m.startsWith("o1") || m.startsWith("o3") || m.startsWith("o4") || m.startsWith("gpt-5") || m.includes("codex");
13592
14463
  }
13593
- function isGeminiThinkingModel(model) {
13594
- const m = model.toLowerCase();
13595
- return m.includes("gemini-2.5-pro") || m.includes("gemini-2.5-flash") || m.includes("gemini-3") && !m.includes("flash-lite") || m.includes("gemini-2.0-flash-thinking");
14464
+ function isGeminiThinkingModel(model2) {
14465
+ const m = model2.toLowerCase();
14466
+ return m.includes("gemini-2.5-pro") || m.includes("gemini-2.5-flash") || m.includes("gemini-3") || m.includes("gemini-2.0-flash-thinking");
14467
+ }
14468
+ function isGeminiLevelThinkingModel(model2) {
14469
+ return model2.toLowerCase().includes("gemini-3");
13596
14470
  }
13597
- function isKimiThinkingModel(model) {
13598
- const m = model.toLowerCase();
14471
+ function isKimiThinkingModel(model2) {
14472
+ const m = model2.toLowerCase();
13599
14473
  return m.includes("kimi-k2") || m === "kimi-latest";
13600
14474
  }
14475
+ var UNSUPPORTED = {
14476
+ supported: false,
14477
+ kinds: [],
14478
+ levels: ["off"],
14479
+ defaultMode: "off"
14480
+ };
13601
14481
  var ANTHROPIC_CAPABILITY = {
13602
- budgetRange: { min: 1024, max: 64e3, default: ANTHROPIC_BUDGET.medium }};
14482
+ supported: true,
14483
+ kinds: ["budget"],
14484
+ levels: ["off", "auto", "low", "medium", "high"],
14485
+ budgetRange: { min: 1024, max: 64e3, default: ANTHROPIC_BUDGET.medium },
14486
+ defaultMode: "off"
14487
+ };
14488
+ var ANTHROPIC_ADAPTIVE_CAPABILITY = {
14489
+ supported: true,
14490
+ kinds: ["effort"],
14491
+ levels: ["off", "auto", "low", "medium", "high"],
14492
+ defaultMode: "off"
14493
+ };
14494
+ var OPENAI_CAPABILITY = {
14495
+ supported: true,
14496
+ kinds: ["effort"],
14497
+ levels: ["off", "auto", "low", "medium", "high"],
14498
+ defaultMode: "medium"
14499
+ };
13603
14500
  var GEMINI_CAPABILITY = {
13604
- budgetRange: { min: 0, max: 32e3}};
13605
- function mapToAnthropic(mode, model) {
14501
+ supported: true,
14502
+ kinds: ["budget"],
14503
+ levels: ["off", "auto", "low", "medium", "high"],
14504
+ budgetRange: { min: 0, max: 32e3, default: GEMINI_BUDGET.medium },
14505
+ defaultMode: "auto"
14506
+ };
14507
+ var GEMINI_LEVEL_CAPABILITY = {
14508
+ supported: true,
14509
+ kinds: ["effort"],
14510
+ levels: ["auto", "low", "medium", "high"],
14511
+ defaultMode: "auto"
14512
+ };
14513
+ var KIMI_CAPABILITY = {
14514
+ supported: true,
14515
+ kinds: ["effort"],
14516
+ levels: ["off", "auto"],
14517
+ defaultMode: "off"
14518
+ };
14519
+ function getThinkingCapability(provider, model2) {
14520
+ switch (provider) {
14521
+ case "anthropic":
14522
+ case "kimi-code":
14523
+ if (isAnthropicAdaptiveThinkingModel(model2)) return ANTHROPIC_ADAPTIVE_CAPABILITY;
14524
+ return isAnthropicThinkingModel(model2) ? ANTHROPIC_CAPABILITY : UNSUPPORTED;
14525
+ case "openai":
14526
+ return isOpenAIReasoningModel(model2) ? OPENAI_CAPABILITY : UNSUPPORTED;
14527
+ case "kimi":
14528
+ return isKimiThinkingModel(model2) ? KIMI_CAPABILITY : UNSUPPORTED;
14529
+ case "gemini":
14530
+ case "vertex":
14531
+ if (isGeminiLevelThinkingModel(model2)) return GEMINI_LEVEL_CAPABILITY;
14532
+ return isGeminiThinkingModel(model2) ? GEMINI_CAPABILITY : UNSUPPORTED;
14533
+ case "copilot":
14534
+ case "groq":
14535
+ case "openrouter":
14536
+ case "mistral":
14537
+ case "deepseek":
14538
+ case "together":
14539
+ case "huggingface":
14540
+ case "qwen":
14541
+ case "lmstudio":
14542
+ case "ollama":
14543
+ case "codex":
14544
+ return UNSUPPORTED;
14545
+ default:
14546
+ return UNSUPPORTED;
14547
+ }
14548
+ }
14549
+ function mapToAnthropic(mode, model2) {
13606
14550
  if (!mode || mode === "off") return void 0;
13607
- if (!isAnthropicThinkingModel(model)) return void 0;
14551
+ if (!isAnthropicThinkingModel(model2)) return void 0;
14552
+ if (isAnthropicAdaptiveThinkingModel(model2)) {
14553
+ return { type: "adaptive" };
14554
+ }
13608
14555
  const cap = ANTHROPIC_CAPABILITY;
13609
14556
  const { min, max } = cap.budgetRange;
13610
14557
  if (typeof mode === "object") {
@@ -13620,9 +14567,20 @@ function mapToAnthropic(mode, model) {
13620
14567
  if (budget === void 0) return void 0;
13621
14568
  return { type: "enabled", budget_tokens: budget };
13622
14569
  }
13623
- function mapToOpenAIEffort(mode, model) {
14570
+ function mapToAnthropicEffort(mode, model2) {
14571
+ if (!mode || mode === "off" || mode === "auto") return void 0;
14572
+ if (!isAnthropicAdaptiveThinkingModel(model2)) return void 0;
14573
+ if (typeof mode === "object") {
14574
+ if (mode.budget <= 2048) return "low";
14575
+ if (mode.budget <= 8e3) return "medium";
14576
+ return "high";
14577
+ }
14578
+ if (mode === "low" || mode === "medium" || mode === "high") return mode;
14579
+ return void 0;
14580
+ }
14581
+ function mapToOpenAIEffort(mode, model2) {
13624
14582
  if (!mode || mode === "off") return void 0;
13625
- if (!isOpenAIReasoningModel(model)) return void 0;
14583
+ if (!isOpenAIReasoningModel(model2)) return void 0;
13626
14584
  if (typeof mode === "object") {
13627
14585
  const { budget } = mode;
13628
14586
  if (budget <= 2048) return "low";
@@ -13633,8 +14591,9 @@ function mapToOpenAIEffort(mode, model) {
13633
14591
  if (mode === "low" || mode === "medium" || mode === "high") return mode;
13634
14592
  return void 0;
13635
14593
  }
13636
- function mapToGeminiBudget(mode, model) {
13637
- if (!isGeminiThinkingModel(model)) return void 0;
14594
+ function mapToGeminiBudget(mode, model2) {
14595
+ if (isGeminiLevelThinkingModel(model2)) return void 0;
14596
+ if (!isGeminiThinkingModel(model2)) return void 0;
13638
14597
  if (!mode) return void 0;
13639
14598
  if (mode === "off") return 0;
13640
14599
  if (mode === "auto") return -1;
@@ -13649,15 +14608,33 @@ function mapToGeminiBudget(mode, model) {
13649
14608
  };
13650
14609
  return budgetMap[mode];
13651
14610
  }
13652
- function mapToKimiExtraBody(mode, model) {
13653
- if (!isKimiThinkingModel(model)) return void 0;
14611
+ function mapToGeminiThinkingConfig(mode, model2) {
14612
+ if (isGeminiLevelThinkingModel(model2)) {
14613
+ if (!mode || mode === "auto") return void 0;
14614
+ if (mode === "off") return { thinkingLevel: "low" };
14615
+ if (mode === "low" || mode === "medium" || mode === "high") {
14616
+ return { thinkingLevel: mode };
14617
+ }
14618
+ if (typeof mode === "object") {
14619
+ if (mode.budget <= 2048) return { thinkingLevel: "low" };
14620
+ if (mode.budget <= 8e3) return { thinkingLevel: "medium" };
14621
+ return { thinkingLevel: "high" };
14622
+ }
14623
+ return void 0;
14624
+ }
14625
+ const thinkingBudget = mapToGeminiBudget(mode, model2);
14626
+ return thinkingBudget !== void 0 ? { thinkingBudget } : void 0;
14627
+ }
14628
+ function mapToKimiExtraBody(mode, model2) {
14629
+ if (!isKimiThinkingModel(model2)) return void 0;
13654
14630
  const effectiveMode = mode ?? "off";
13655
14631
  const enabled = effectiveMode !== "off";
13656
14632
  return { thinking: { type: enabled ? "enabled" : "disabled" } };
13657
14633
  }
13658
14634
 
13659
14635
  // src/providers/anthropic.ts
13660
- var DEFAULT_MODEL = "claude-opus-4-6";
14636
+ init_catalog();
14637
+ var DEFAULT_MODEL = getCatalogDefaultModel("anthropic");
13661
14638
  var CONTEXT_WINDOWS = {
13662
14639
  // Kimi Code model (Anthropic-compatible endpoint)
13663
14640
  "kimi-for-coding": 131072,
@@ -13683,6 +14660,20 @@ var CONTEXT_WINDOWS = {
13683
14660
  "claude-3-sonnet-20240229": 2e5,
13684
14661
  "claude-3-haiku-20240307": 2e5
13685
14662
  };
14663
+ function getAnthropicMaxTokens(baseMaxTokens, thinkingParam) {
14664
+ if (thinkingParam?.type === "enabled") {
14665
+ return Math.max(baseMaxTokens, thinkingParam.budget_tokens + 1024);
14666
+ }
14667
+ return baseMaxTokens;
14668
+ }
14669
+ function getAnthropicTemperature(thinkingParam, configuredTemperature) {
14670
+ if (thinkingParam?.type === "enabled") return 1;
14671
+ return configuredTemperature;
14672
+ }
14673
+ function getAnthropicOutputConfig(mode, model2) {
14674
+ const effort = mapToAnthropicEffort(mode, model2);
14675
+ return effort ? { effort } : void 0;
14676
+ }
13686
14677
  var AnthropicProvider = class {
13687
14678
  id;
13688
14679
  name;
@@ -13717,19 +14708,22 @@ var AnthropicProvider = class {
13717
14708
  this.ensureInitialized();
13718
14709
  return withRetry(async () => {
13719
14710
  try {
13720
- const model = options?.model ?? this.config.model ?? DEFAULT_MODEL;
13721
- const thinkingParam = mapToAnthropic(options?.thinking, model);
14711
+ const model2 = options?.model ?? this.config.model ?? DEFAULT_MODEL;
14712
+ const thinkingParam = mapToAnthropic(options?.thinking, model2);
14713
+ const outputConfig = getAnthropicOutputConfig(options?.thinking, model2);
13722
14714
  const baseMaxTokens = options?.maxTokens ?? this.config.maxTokens ?? 8192;
13723
14715
  const response = await this.client.messages.create({
13724
- model,
13725
- // Anthropic requires max_tokens > budget_tokens
13726
- max_tokens: thinkingParam ? Math.max(baseMaxTokens, thinkingParam.budget_tokens + 1024) : baseMaxTokens,
13727
- // Anthropic requires temperature=1 when thinking is enabled
13728
- temperature: thinkingParam ? 1 : options?.temperature ?? this.config.temperature ?? 0,
14716
+ model: model2,
14717
+ max_tokens: getAnthropicMaxTokens(baseMaxTokens, thinkingParam),
14718
+ temperature: getAnthropicTemperature(
14719
+ thinkingParam,
14720
+ options?.temperature ?? this.config.temperature ?? 0
14721
+ ),
13729
14722
  system: this.extractSystem(messages, options?.system),
13730
14723
  messages: this.convertMessages(messages),
13731
14724
  stop_sequences: options?.stopSequences,
13732
- ...thinkingParam && { thinking: thinkingParam }
14725
+ ...thinkingParam && { thinking: thinkingParam },
14726
+ ...outputConfig && { output_config: outputConfig }
13733
14727
  });
13734
14728
  return {
13735
14729
  id: response.id,
@@ -13753,18 +14747,23 @@ var AnthropicProvider = class {
13753
14747
  this.ensureInitialized();
13754
14748
  return withRetry(async () => {
13755
14749
  try {
13756
- const model = options?.model ?? this.config.model ?? DEFAULT_MODEL;
13757
- const thinkingParam = mapToAnthropic(options?.thinking, model);
14750
+ const model2 = options?.model ?? this.config.model ?? DEFAULT_MODEL;
14751
+ const thinkingParam = mapToAnthropic(options?.thinking, model2);
14752
+ const outputConfig = getAnthropicOutputConfig(options?.thinking, model2);
13758
14753
  const baseMaxTokens = options?.maxTokens ?? this.config.maxTokens ?? 8192;
13759
14754
  const response = await this.client.messages.create({
13760
- model,
13761
- max_tokens: thinkingParam ? Math.max(baseMaxTokens, thinkingParam.budget_tokens + 1024) : baseMaxTokens,
13762
- temperature: thinkingParam ? 1 : options?.temperature ?? this.config.temperature ?? 0,
14755
+ model: model2,
14756
+ max_tokens: getAnthropicMaxTokens(baseMaxTokens, thinkingParam),
14757
+ temperature: getAnthropicTemperature(
14758
+ thinkingParam,
14759
+ options?.temperature ?? this.config.temperature ?? 0
14760
+ ),
13763
14761
  system: this.extractSystem(messages, options?.system),
13764
14762
  messages: this.convertMessages(messages),
13765
14763
  tools: this.convertTools(options.tools),
13766
14764
  tool_choice: options.toolChoice ? this.convertToolChoice(options.toolChoice) : void 0,
13767
- ...thinkingParam && { thinking: thinkingParam }
14765
+ ...thinkingParam && { thinking: thinkingParam },
14766
+ ...outputConfig && { output_config: outputConfig }
13768
14767
  });
13769
14768
  const toolCalls = this.extractToolCalls(response.content);
13770
14769
  return {
@@ -13790,17 +14789,22 @@ var AnthropicProvider = class {
13790
14789
  this.ensureInitialized();
13791
14790
  let timeoutTriggered = false;
13792
14791
  try {
13793
- const model = options?.model ?? this.config.model ?? DEFAULT_MODEL;
13794
- const thinkingParam = mapToAnthropic(options?.thinking, model);
14792
+ const model2 = options?.model ?? this.config.model ?? DEFAULT_MODEL;
14793
+ const thinkingParam = mapToAnthropic(options?.thinking, model2);
14794
+ const outputConfig = getAnthropicOutputConfig(options?.thinking, model2);
13795
14795
  const baseMaxTokens = options?.maxTokens ?? this.config.maxTokens ?? 8192;
13796
14796
  const stream = await this.client.messages.stream(
13797
14797
  {
13798
- model,
13799
- max_tokens: thinkingParam ? Math.max(baseMaxTokens, thinkingParam.budget_tokens + 1024) : baseMaxTokens,
13800
- temperature: thinkingParam ? 1 : options?.temperature ?? this.config.temperature ?? 0,
14798
+ model: model2,
14799
+ max_tokens: getAnthropicMaxTokens(baseMaxTokens, thinkingParam),
14800
+ temperature: getAnthropicTemperature(
14801
+ thinkingParam,
14802
+ options?.temperature ?? this.config.temperature ?? 0
14803
+ ),
13801
14804
  system: this.extractSystem(messages, options?.system),
13802
14805
  messages: this.convertMessages(messages),
13803
- ...thinkingParam && { thinking: thinkingParam }
14806
+ ...thinkingParam && { thinking: thinkingParam },
14807
+ ...outputConfig && { output_config: outputConfig }
13804
14808
  },
13805
14809
  { signal: options?.signal }
13806
14810
  );
@@ -13856,19 +14860,24 @@ var AnthropicProvider = class {
13856
14860
  this.ensureInitialized();
13857
14861
  let timeoutTriggered = false;
13858
14862
  try {
13859
- const model = options?.model ?? this.config.model ?? DEFAULT_MODEL;
13860
- const thinkingParam = mapToAnthropic(options?.thinking, model);
14863
+ const model2 = options?.model ?? this.config.model ?? DEFAULT_MODEL;
14864
+ const thinkingParam = mapToAnthropic(options?.thinking, model2);
14865
+ const outputConfig = getAnthropicOutputConfig(options?.thinking, model2);
13861
14866
  const baseMaxTokens = options?.maxTokens ?? this.config.maxTokens ?? 8192;
13862
14867
  const stream = await this.client.messages.stream(
13863
14868
  {
13864
- model,
13865
- max_tokens: thinkingParam ? Math.max(baseMaxTokens, thinkingParam.budget_tokens + 1024) : baseMaxTokens,
13866
- temperature: thinkingParam ? 1 : options?.temperature ?? this.config.temperature ?? 0,
14869
+ model: model2,
14870
+ max_tokens: getAnthropicMaxTokens(baseMaxTokens, thinkingParam),
14871
+ temperature: getAnthropicTemperature(
14872
+ thinkingParam,
14873
+ options?.temperature ?? this.config.temperature ?? 0
14874
+ ),
13867
14875
  system: this.extractSystem(messages, options?.system),
13868
14876
  messages: this.convertMessages(messages),
13869
14877
  tools: this.convertTools(options.tools),
13870
14878
  tool_choice: options.toolChoice ? this.convertToolChoice(options.toolChoice) : void 0,
13871
- ...thinkingParam && { thinking: thinkingParam }
14879
+ ...thinkingParam && { thinking: thinkingParam },
14880
+ ...outputConfig && { output_config: outputConfig }
13872
14881
  },
13873
14882
  { signal: options?.signal }
13874
14883
  );
@@ -13993,33 +15002,38 @@ var AnthropicProvider = class {
13993
15002
  *
13994
15003
  * This heuristic analyzes the text to provide a better estimate.
13995
15004
  */
13996
- countTokens(text) {
13997
- if (!text) return 0;
15005
+ countTokens(text2) {
15006
+ if (!text2) return 0;
13998
15007
  const codePatterns = /[{}[\]();=<>!&|+\-*/]/g;
13999
15008
  const whitespacePattern = /\s/g;
14000
15009
  const wordPattern = /\b\w+\b/g;
14001
- const codeChars = (text.match(codePatterns) || []).length;
14002
- const whitespace = (text.match(whitespacePattern) || []).length;
14003
- const words = (text.match(wordPattern) || []).length;
14004
- const isCodeLike = codeChars > text.length * 0.05;
15010
+ const codeChars = (text2.match(codePatterns) || []).length;
15011
+ const whitespace = (text2.match(whitespacePattern) || []).length;
15012
+ const words = (text2.match(wordPattern) || []).length;
15013
+ const isCodeLike = codeChars > text2.length * 0.05;
14005
15014
  let charsPerToken;
14006
15015
  if (isCodeLike) {
14007
15016
  charsPerToken = 3.5;
14008
- } else if (whitespace > text.length * 0.3) {
15017
+ } else if (whitespace > text2.length * 0.3) {
14009
15018
  charsPerToken = 5;
14010
15019
  } else {
14011
15020
  charsPerToken = 4.5;
14012
15021
  }
14013
15022
  const wordBasedEstimate = words * 1.3;
14014
- const charBasedEstimate = text.length / charsPerToken;
15023
+ const charBasedEstimate = text2.length / charsPerToken;
14015
15024
  return Math.ceil((wordBasedEstimate + charBasedEstimate) / 2);
14016
15025
  }
14017
15026
  /**
14018
15027
  * Get context window size
14019
15028
  */
14020
15029
  getContextWindow() {
14021
- const model = this.config.model ?? DEFAULT_MODEL;
14022
- return CONTEXT_WINDOWS[model] ?? 2e5;
15030
+ const model2 = this.config.model ?? DEFAULT_MODEL;
15031
+ const provider = this.id === "kimi-code" ? "kimi-code" : "anthropic";
15032
+ const catalogWindow = getCatalogContextWindow(provider, model2, 0);
15033
+ if (catalogWindow > 0) {
15034
+ return catalogWindow;
15035
+ }
15036
+ return CONTEXT_WINDOWS[model2] ?? 2e5;
14023
15037
  }
14024
15038
  /**
14025
15039
  * Check if provider is available
@@ -14060,8 +15074,8 @@ var AnthropicProvider = class {
14060
15074
  const systemMsg = messages.find((m) => m.role === "system");
14061
15075
  if (!systemMsg) return void 0;
14062
15076
  if (typeof systemMsg.content === "string") return systemMsg.content;
14063
- const text = systemMsg.content.filter((b) => b.type === "text").map((b) => b.text).join("");
14064
- return text || void 0;
15077
+ const text2 = systemMsg.content.filter((b) => b.type === "text").map((b) => b.text).join("");
15078
+ return text2 || void 0;
14065
15079
  }
14066
15080
  /**
14067
15081
  * Convert messages to Anthropic format
@@ -14269,15 +15283,15 @@ var ChatToolCallAssembler = class {
14269
15283
  if (delta.function?.name) {
14270
15284
  builder.name = delta.function.name;
14271
15285
  }
14272
- const text = delta.function?.arguments ?? "";
14273
- if (!text) return { started };
14274
- builder.arguments += text;
15286
+ const text2 = delta.function?.arguments ?? "";
15287
+ if (!text2) return { started };
15288
+ builder.arguments += text2;
14275
15289
  return {
14276
15290
  started,
14277
15291
  argumentDelta: {
14278
15292
  id: builder.id,
14279
15293
  name: builder.name,
14280
- text
15294
+ text: text2
14281
15295
  }
14282
15296
  };
14283
15297
  }
@@ -14368,8 +15382,132 @@ var ResponsesToolCallAssembler = class {
14368
15382
  }
14369
15383
  };
14370
15384
 
15385
+ // src/providers/model-tier.ts
15386
+ var TIER_CONFIGS = {
15387
+ mini: {
15388
+ maxTools: 12,
15389
+ parallelToolCalls: false,
15390
+ compactionThreshold: 0.5,
15391
+ supportsCoT: false
15392
+ },
15393
+ standard: {
15394
+ maxTools: 40,
15395
+ parallelToolCalls: true,
15396
+ compactionThreshold: 0.75,
15397
+ supportsCoT: true
15398
+ },
15399
+ advanced: {
15400
+ maxTools: 128,
15401
+ parallelToolCalls: true,
15402
+ compactionThreshold: 0.8,
15403
+ supportsCoT: true
15404
+ }
15405
+ };
15406
+ var ANTHROPIC_TIERS = [
15407
+ // Haiku — mini tier
15408
+ { prefix: "claude-haiku", tier: "mini" },
15409
+ { prefix: "claude-3-haiku", tier: "mini" },
15410
+ // Sonnet / Claude 3.5 — standard tier
15411
+ { prefix: "claude-3-5-sonnet", tier: "standard" },
15412
+ { prefix: "claude-3-7-sonnet", tier: "standard" },
15413
+ { prefix: "claude-sonnet", tier: "standard" },
15414
+ // Opus — advanced tier
15415
+ { prefix: "claude-opus", tier: "advanced" },
15416
+ { prefix: "claude-3-opus", tier: "advanced" }
15417
+ // claude-4+ (future) — default to standard unless matched above
15418
+ ];
15419
+ var OPENAI_TIERS = [
15420
+ // Mini models
15421
+ { prefix: "gpt-4o-mini", tier: "mini" },
15422
+ { prefix: "gpt-5-mini", tier: "mini" },
15423
+ { prefix: "gpt-5.4-mini", tier: "mini" },
15424
+ { prefix: "gpt-5.3-mini", tier: "mini" },
15425
+ { prefix: "o1-mini", tier: "mini" },
15426
+ { prefix: "o3-mini", tier: "mini" },
15427
+ // Advanced / reasoning models
15428
+ { prefix: "o1", tier: "advanced" },
15429
+ { prefix: "o3", tier: "advanced" },
15430
+ { prefix: "o4", tier: "advanced" },
15431
+ { prefix: "gpt-4.1", tier: "advanced" },
15432
+ { prefix: "gpt-5.4-codex", tier: "advanced" },
15433
+ { prefix: "gpt-5.3-codex", tier: "advanced" },
15434
+ { prefix: "gpt-5.2-codex", tier: "advanced" },
15435
+ { prefix: "gpt-5.1-codex", tier: "advanced" },
15436
+ { prefix: "gpt-5.4", tier: "advanced" },
15437
+ { prefix: "gpt-5.3", tier: "advanced" },
15438
+ { prefix: "gpt-5.2", tier: "advanced" },
15439
+ { prefix: "gpt-5.1", tier: "advanced" },
15440
+ // GPT-5 catch-all (non-mini/codex) — advanced
15441
+ { prefix: "gpt-5", tier: "advanced" },
15442
+ // GPT-4o — standard
15443
+ { prefix: "gpt-4o", tier: "standard" },
15444
+ // GPT-4 — standard
15445
+ { prefix: "gpt-4", tier: "standard" }
15446
+ ];
15447
+ var GEMINI_TIERS = [
15448
+ // Flash — mini tier
15449
+ { prefix: "gemini-3-flash", tier: "mini" },
15450
+ { prefix: "gemini-2.5-flash", tier: "mini" },
15451
+ { prefix: "gemini-2.0-flash", tier: "mini" },
15452
+ { prefix: "gemini-1.5-flash", tier: "mini" },
15453
+ // Pro — standard/advanced
15454
+ { prefix: "gemini-3.1-pro", tier: "advanced" },
15455
+ { prefix: "gemini-3-pro", tier: "advanced" },
15456
+ { prefix: "gemini-2.5-pro", tier: "standard" },
15457
+ { prefix: "gemini-2.0-pro", tier: "standard" },
15458
+ { prefix: "gemini-1.5-pro", tier: "standard" }
15459
+ ];
15460
+ var KIMI_TIERS = [
15461
+ { prefix: "kimi-for-coding", tier: "advanced" },
15462
+ { prefix: "kimi-k2", tier: "advanced" },
15463
+ { prefix: "kimi-latest", tier: "standard" },
15464
+ { prefix: "kimi", tier: "standard" }
15465
+ ];
15466
+ var EVAL_TIERS = [
15467
+ { prefix: "grok-code", tier: "standard" },
15468
+ { prefix: "raptor", tier: "mini" },
15469
+ { prefix: "goldeneye", tier: "standard" }
15470
+ ];
15471
+ function matchTier(model2, table) {
15472
+ const lower = model2.toLowerCase();
15473
+ const sorted = [...table].sort((a, b) => b.prefix.length - a.prefix.length);
15474
+ for (const { prefix, tier } of sorted) {
15475
+ if (lower.startsWith(prefix.toLowerCase())) return tier;
15476
+ }
15477
+ return null;
15478
+ }
15479
+ function getModelTier(provider, model2) {
15480
+ if (!model2) return "standard";
15481
+ const p5 = provider.toLowerCase();
15482
+ if (p5 === "anthropic") {
15483
+ return matchTier(model2, ANTHROPIC_TIERS) ?? "standard";
15484
+ }
15485
+ if (p5 === "kimi-code") {
15486
+ return matchTier(model2, KIMI_TIERS) ?? matchTier(model2, ANTHROPIC_TIERS) ?? "standard";
15487
+ }
15488
+ if (p5 === "openai" || p5 === "copilot" || p5 === "codex") {
15489
+ if (model2.startsWith("claude-")) {
15490
+ return matchTier(model2, ANTHROPIC_TIERS) ?? "standard";
15491
+ }
15492
+ const evalMatch = matchTier(model2, EVAL_TIERS);
15493
+ if (evalMatch) return evalMatch;
15494
+ return matchTier(model2, OPENAI_TIERS) ?? "standard";
15495
+ }
15496
+ if (p5 === "gemini" || p5 === "vertex") {
15497
+ return matchTier(model2, GEMINI_TIERS) ?? "standard";
15498
+ }
15499
+ if (p5 === "kimi" || p5 === "moonshot") {
15500
+ return matchTier(model2, KIMI_TIERS) ?? "standard";
15501
+ }
15502
+ return "standard";
15503
+ }
15504
+ function getTierConfig(provider, model2) {
15505
+ return TIER_CONFIGS[getModelTier(provider, model2)];
15506
+ }
15507
+
14371
15508
  // src/providers/openai.ts
14372
- var DEFAULT_MODEL2 = "gpt-5.3-codex";
15509
+ init_catalog();
15510
+ var DEFAULT_MODEL2 = getCatalogDefaultModel("openai");
14373
15511
  var CONTEXT_WINDOWS2 = {
14374
15512
  // OpenAI models
14375
15513
  "gpt-4o": 128e3,
@@ -14480,14 +15618,14 @@ var LOCAL_MODEL_PATTERNS = [
14480
15618
  "starcoder"
14481
15619
  ];
14482
15620
  var MODELS_WITH_THINKING_MODE = ["kimi-k2.5", "kimi-k2-0324", "kimi-latest"];
14483
- function needsResponsesApi(model) {
14484
- return model.includes("codex") || model.startsWith("gpt-5") || model.startsWith("o4-") || model === "o3";
15621
+ function needsResponsesApi(model2) {
15622
+ return model2.includes("codex") || model2.startsWith("gpt-5") || model2.startsWith("o4-") || model2 === "o3";
14485
15623
  }
14486
- function needsMaxCompletionTokens(model) {
14487
- return model.startsWith("o1") || model.startsWith("o3") || model.startsWith("o4") || model.startsWith("gpt-4o") || model.startsWith("gpt-4.1") || model.startsWith("gpt-5") || model.startsWith("chatgpt-4o");
15624
+ function needsMaxCompletionTokens(model2) {
15625
+ return model2.startsWith("o1") || model2.startsWith("o3") || model2.startsWith("o4") || model2.startsWith("gpt-4o") || model2.startsWith("gpt-4.1") || model2.startsWith("gpt-5") || model2.startsWith("chatgpt-4o");
14488
15626
  }
14489
- function buildMaxTokensParam(model, maxTokens) {
14490
- if (needsMaxCompletionTokens(model)) {
15627
+ function buildMaxTokensParam(model2, maxTokens) {
15628
+ if (needsMaxCompletionTokens(model2)) {
14491
15629
  return { max_completion_tokens: maxTokens };
14492
15630
  }
14493
15631
  return { max_tokens: maxTokens };
@@ -14529,26 +15667,45 @@ var OpenAIProvider = class {
14529
15667
  /**
14530
15668
  * Check if a model supports temperature parameter
14531
15669
  */
14532
- supportsTemperature(model) {
14533
- return !MODELS_WITHOUT_TEMPERATURE.some((m) => model.toLowerCase().includes(m.toLowerCase()));
15670
+ supportsTemperature(model2) {
15671
+ return !MODELS_WITHOUT_TEMPERATURE.some((m) => model2.toLowerCase().includes(m.toLowerCase()));
14534
15672
  }
14535
15673
  /**
14536
15674
  * Whether this provider instance supports the Responses API for the given model.
14537
15675
  * Subclasses (e.g. CopilotProvider) can override to force Chat Completions
14538
15676
  * when their endpoint does not expose /v1/responses.
14539
15677
  */
14540
- modelNeedsResponsesApi(model) {
14541
- return needsResponsesApi(model);
15678
+ modelNeedsResponsesApi(model2) {
15679
+ return this.id === "openai" && needsResponsesApi(model2);
15680
+ }
15681
+ /**
15682
+ * Map thinking mode to Chat Completions reasoning_effort.
15683
+ * Subclasses can override when an OpenAI-compatible endpoint exposes GPT-5
15684
+ * models but cannot safely combine reasoning_effort with tool calls.
15685
+ */
15686
+ getChatCompletionsReasoningEffort(model2, thinking, _hasTools) {
15687
+ const capability = getThinkingCapability(this.id, model2);
15688
+ if (!capability.supported || !capability.kinds.includes("effort")) {
15689
+ return void 0;
15690
+ }
15691
+ return mapToOpenAIEffort(thinking, model2);
15692
+ }
15693
+ getResponsesReasoningEffort(model2, thinking) {
15694
+ const capability = getThinkingCapability(this.id, model2);
15695
+ if (!capability.supported || !capability.kinds.includes("effort")) {
15696
+ return void 0;
15697
+ }
15698
+ return mapToOpenAIEffort(thinking, model2);
14542
15699
  }
14543
15700
  /**
14544
15701
  * Get extra body parameters for API calls.
14545
15702
  * Honors the user's ThinkingMode for Kimi models; defaults to disabled
14546
15703
  * (preserving existing behavior) when no mode is specified.
14547
15704
  */
14548
- getExtraBody(model, thinking) {
14549
- const kimiBody = mapToKimiExtraBody(thinking, model);
15705
+ getExtraBody(model2, thinking) {
15706
+ const kimiBody = mapToKimiExtraBody(thinking, model2);
14550
15707
  if (kimiBody) return kimiBody;
14551
- if (MODELS_WITH_THINKING_MODE.some((m) => model.toLowerCase().includes(m.toLowerCase()))) {
15708
+ if (MODELS_WITH_THINKING_MODE.some((m) => model2.toLowerCase().includes(m.toLowerCase()))) {
14552
15709
  return { thinking: { type: "disabled" } };
14553
15710
  }
14554
15711
  return void 0;
@@ -14558,18 +15715,22 @@ var OpenAIProvider = class {
14558
15715
  */
14559
15716
  async chat(messages, options) {
14560
15717
  this.ensureInitialized();
14561
- const model = options?.model ?? this.config.model ?? DEFAULT_MODEL2;
14562
- if (this.modelNeedsResponsesApi(model)) {
15718
+ const model2 = options?.model ?? this.config.model ?? DEFAULT_MODEL2;
15719
+ if (this.modelNeedsResponsesApi(model2)) {
14563
15720
  return this.chatViaResponses(messages, options);
14564
15721
  }
14565
15722
  return withRetry(async () => {
14566
15723
  try {
14567
- const supportsTemp = this.supportsTemperature(model);
15724
+ const supportsTemp = this.supportsTemperature(model2);
14568
15725
  const maxTokens = options?.maxTokens ?? this.config.maxTokens ?? 8192;
14569
- const reasoningEffort = mapToOpenAIEffort(options?.thinking, model);
15726
+ const reasoningEffort = this.getChatCompletionsReasoningEffort(
15727
+ model2,
15728
+ options?.thinking,
15729
+ false
15730
+ );
14570
15731
  const response = await this.client.chat.completions.create({
14571
- model,
14572
- ...buildMaxTokensParam(model, maxTokens),
15732
+ model: model2,
15733
+ ...buildMaxTokensParam(model2, maxTokens),
14573
15734
  messages: this.convertMessages(messages, options?.system),
14574
15735
  stop: options?.stopSequences,
14575
15736
  ...supportsTemp && {
@@ -14598,22 +15759,29 @@ var OpenAIProvider = class {
14598
15759
  */
14599
15760
  async chatWithTools(messages, options) {
14600
15761
  this.ensureInitialized();
14601
- const model = options?.model ?? this.config.model ?? DEFAULT_MODEL2;
14602
- if (this.modelNeedsResponsesApi(model)) {
15762
+ const model2 = options?.model ?? this.config.model ?? DEFAULT_MODEL2;
15763
+ if (this.modelNeedsResponsesApi(model2)) {
14603
15764
  return this.chatWithToolsViaResponses(messages, options);
14604
15765
  }
15766
+ const tierCfg = getTierConfig(this.id, model2);
14605
15767
  return withRetry(async () => {
14606
15768
  try {
14607
- const supportsTemp = this.supportsTemperature(model);
14608
- const extraBody = this.getExtraBody(model, options?.thinking);
14609
- const reasoningEffort = mapToOpenAIEffort(options?.thinking, model);
15769
+ const supportsTemp = this.supportsTemperature(model2);
15770
+ const extraBody = this.getExtraBody(model2, options?.thinking);
15771
+ const reasoningEffort = this.getChatCompletionsReasoningEffort(
15772
+ model2,
15773
+ options?.thinking,
15774
+ true
15775
+ );
14610
15776
  const maxTokens = options?.maxTokens ?? this.config.maxTokens ?? 8192;
15777
+ const tools = this.limitTools(options.tools, tierCfg.maxTools);
14611
15778
  const requestParams = {
14612
- model,
14613
- ...buildMaxTokensParam(model, maxTokens),
15779
+ model: model2,
15780
+ ...buildMaxTokensParam(model2, maxTokens),
14614
15781
  messages: this.convertMessages(messages, options?.system),
14615
- tools: this.convertTools(options.tools),
14616
- tool_choice: this.convertToolChoice(options.toolChoice)
15782
+ tools: this.convertTools(tools),
15783
+ tool_choice: this.convertToolChoice(options.toolChoice),
15784
+ parallel_tool_calls: tierCfg.parallelToolCalls
14617
15785
  };
14618
15786
  if (supportsTemp) {
14619
15787
  requestParams.temperature = options?.temperature ?? this.config.temperature ?? 0;
@@ -14650,18 +15818,22 @@ var OpenAIProvider = class {
14650
15818
  */
14651
15819
  async *stream(messages, options) {
14652
15820
  this.ensureInitialized();
14653
- const model = options?.model ?? this.config.model ?? DEFAULT_MODEL2;
14654
- if (this.modelNeedsResponsesApi(model)) {
15821
+ const model2 = options?.model ?? this.config.model ?? DEFAULT_MODEL2;
15822
+ if (this.modelNeedsResponsesApi(model2)) {
14655
15823
  yield* this.streamViaResponses(messages, options);
14656
15824
  return;
14657
15825
  }
14658
15826
  try {
14659
- const supportsTemp = this.supportsTemperature(model);
15827
+ const supportsTemp = this.supportsTemperature(model2);
14660
15828
  const maxTokens = options?.maxTokens ?? this.config.maxTokens ?? 8192;
14661
- const reasoningEffort = mapToOpenAIEffort(options?.thinking, model);
15829
+ const reasoningEffort = this.getChatCompletionsReasoningEffort(
15830
+ model2,
15831
+ options?.thinking,
15832
+ false
15833
+ );
14662
15834
  const stream = await this.client.chat.completions.create({
14663
- model,
14664
- ...buildMaxTokensParam(model, maxTokens),
15835
+ model: model2,
15836
+ ...buildMaxTokensParam(model2, maxTokens),
14665
15837
  messages: this.convertMessages(messages, options?.system),
14666
15838
  stream: true,
14667
15839
  ...supportsTemp && { temperature: options?.temperature ?? this.config.temperature ?? 0 },
@@ -14688,23 +15860,30 @@ var OpenAIProvider = class {
14688
15860
  */
14689
15861
  async *streamWithTools(messages, options) {
14690
15862
  this.ensureInitialized();
14691
- const model = options?.model ?? this.config.model ?? DEFAULT_MODEL2;
14692
- if (this.modelNeedsResponsesApi(model)) {
15863
+ const model2 = options?.model ?? this.config.model ?? DEFAULT_MODEL2;
15864
+ if (this.modelNeedsResponsesApi(model2)) {
14693
15865
  yield* this.streamWithToolsViaResponses(messages, options);
14694
15866
  return;
14695
15867
  }
15868
+ const tierCfg = getTierConfig(this.id, model2);
14696
15869
  let timeoutTriggered = false;
14697
15870
  try {
14698
- const supportsTemp = this.supportsTemperature(model);
14699
- const extraBody = this.getExtraBody(model, options?.thinking);
14700
- const reasoningEffort = mapToOpenAIEffort(options?.thinking, model);
15871
+ const supportsTemp = this.supportsTemperature(model2);
15872
+ const extraBody = this.getExtraBody(model2, options?.thinking);
15873
+ const reasoningEffort = this.getChatCompletionsReasoningEffort(
15874
+ model2,
15875
+ options?.thinking,
15876
+ true
15877
+ );
14701
15878
  const maxTokens = options?.maxTokens ?? this.config.maxTokens ?? 8192;
15879
+ const tools = this.limitTools(options.tools, tierCfg.maxTools);
14702
15880
  const requestParams = {
14703
- model,
14704
- ...buildMaxTokensParam(model, maxTokens),
15881
+ model: model2,
15882
+ ...buildMaxTokensParam(model2, maxTokens),
14705
15883
  messages: this.convertMessages(messages, options?.system),
14706
- tools: this.convertTools(options.tools),
15884
+ tools: this.convertTools(tools),
14707
15885
  tool_choice: this.convertToolChoice(options.toolChoice),
15886
+ parallel_tool_calls: tierCfg.parallelToolCalls,
14708
15887
  stream: true
14709
15888
  };
14710
15889
  if (supportsTemp) {
@@ -14821,13 +16000,13 @@ var OpenAIProvider = class {
14821
16000
  * Check if current model is a local model (LM Studio, Ollama, etc.)
14822
16001
  */
14823
16002
  isLocalModel() {
14824
- const model = (this.config.model ?? "").toLowerCase();
16003
+ const model2 = (this.config.model ?? "").toLowerCase();
14825
16004
  const baseUrl = (this.config.baseUrl ?? "").toLowerCase();
14826
16005
  if (baseUrl.includes("localhost") || baseUrl.includes("127.0.0.1") || baseUrl.includes(":1234") || // LM Studio default
14827
16006
  baseUrl.includes(":11434")) {
14828
16007
  return true;
14829
16008
  }
14830
- return LOCAL_MODEL_PATTERNS.some((pattern) => model.includes(pattern));
16009
+ return LOCAL_MODEL_PATTERNS.some((pattern) => model2.includes(pattern));
14831
16010
  }
14832
16011
  /**
14833
16012
  * Count tokens (improved heuristic for OpenAI and local models)
@@ -14847,23 +16026,23 @@ var OpenAIProvider = class {
14847
16026
  * For accurate counting, use the model's native tokenizer.
14848
16027
  * This heuristic provides a reasonable estimate without dependencies.
14849
16028
  */
14850
- countTokens(text) {
14851
- if (!text) return 0;
16029
+ countTokens(text2) {
16030
+ if (!text2) return 0;
14852
16031
  const codePatterns = /[{}[\]();=<>!&|+\-*/]/g;
14853
16032
  const whitespacePattern = /\s/g;
14854
16033
  const wordPattern = /\b\w+\b/g;
14855
16034
  const nonAsciiPattern = /[^\x00-\x7F]/g;
14856
- const codeChars = (text.match(codePatterns) || []).length;
14857
- const whitespace = (text.match(whitespacePattern) || []).length;
14858
- const words = (text.match(wordPattern) || []).length;
14859
- const nonAscii = (text.match(nonAsciiPattern) || []).length;
14860
- const isCodeLike = codeChars > text.length * 0.05;
16035
+ const codeChars = (text2.match(codePatterns) || []).length;
16036
+ const whitespace = (text2.match(whitespacePattern) || []).length;
16037
+ const words = (text2.match(wordPattern) || []).length;
16038
+ const nonAscii = (text2.match(nonAsciiPattern) || []).length;
16039
+ const isCodeLike = codeChars > text2.length * 0.05;
14861
16040
  const isLocal = this.isLocalModel();
14862
16041
  let charsPerToken;
14863
16042
  if (isLocal) {
14864
16043
  if (isCodeLike) {
14865
16044
  charsPerToken = 3.2;
14866
- } else if (nonAscii > text.length * 0.1) {
16045
+ } else if (nonAscii > text2.length * 0.1) {
14867
16046
  charsPerToken = 2;
14868
16047
  } else {
14869
16048
  charsPerToken = 3.5;
@@ -14871,7 +16050,7 @@ var OpenAIProvider = class {
14871
16050
  } else {
14872
16051
  if (isCodeLike) {
14873
16052
  charsPerToken = 3.3;
14874
- } else if (whitespace > text.length * 0.3) {
16053
+ } else if (whitespace > text2.length * 0.3) {
14875
16054
  charsPerToken = 4.5;
14876
16055
  } else {
14877
16056
  charsPerToken = 4;
@@ -14879,7 +16058,7 @@ var OpenAIProvider = class {
14879
16058
  }
14880
16059
  const tokensPerWord = isLocal ? 1.4 : 1.3;
14881
16060
  const wordBasedEstimate = words * tokensPerWord;
14882
- const charBasedEstimate = text.length / charsPerToken;
16061
+ const charBasedEstimate = text2.length / charsPerToken;
14883
16062
  const weight = isCodeLike ? 0.7 : 0.5;
14884
16063
  return Math.ceil(charBasedEstimate * weight + wordBasedEstimate * (1 - weight));
14885
16064
  }
@@ -14891,11 +16070,15 @@ var OpenAIProvider = class {
14891
16070
  * conventions (e.g., "qwen3-coder-8b" vs "qwen3-coder-8b-instruct").
14892
16071
  */
14893
16072
  getContextWindow() {
14894
- const model = this.config.model ?? DEFAULT_MODEL2;
14895
- if (CONTEXT_WINDOWS2[model]) {
14896
- return CONTEXT_WINDOWS2[model];
16073
+ const model2 = this.config.model ?? DEFAULT_MODEL2;
16074
+ if (CONTEXT_WINDOWS2[model2]) {
16075
+ return CONTEXT_WINDOWS2[model2];
14897
16076
  }
14898
- const modelLower = model.toLowerCase();
16077
+ const catalogWindow = getCatalogContextWindow(this.id, model2, 0);
16078
+ if (catalogWindow > 0) {
16079
+ return catalogWindow;
16080
+ }
16081
+ const modelLower = model2.toLowerCase();
14899
16082
  for (const [key, value] of Object.entries(CONTEXT_WINDOWS2)) {
14900
16083
  if (modelLower.includes(key.toLowerCase()) || key.toLowerCase().includes(modelLower)) {
14901
16084
  return value;
@@ -14940,19 +16123,19 @@ var OpenAIProvider = class {
14940
16123
  return true;
14941
16124
  } catch {
14942
16125
  try {
14943
- const model = this.config.model || DEFAULT_MODEL2;
14944
- if (this.modelNeedsResponsesApi(model)) {
16126
+ const model2 = this.config.model || DEFAULT_MODEL2;
16127
+ if (this.modelNeedsResponsesApi(model2)) {
14945
16128
  await this.client.responses.create({
14946
- model,
16129
+ model: model2,
14947
16130
  input: [{ role: "user", content: [{ type: "input_text", text: "Hi" }] }],
14948
16131
  max_output_tokens: 1,
14949
16132
  store: false
14950
16133
  });
14951
16134
  } else {
14952
16135
  await this.client.chat.completions.create({
14953
- model,
16136
+ model: model2,
14954
16137
  messages: [{ role: "user", content: "Hi" }],
14955
- ...buildMaxTokensParam(model, 1)
16138
+ ...buildMaxTokensParam(model2, 1)
14956
16139
  });
14957
16140
  }
14958
16141
  return true;
@@ -15074,6 +16257,17 @@ var OpenAIProvider = class {
15074
16257
  }
15075
16258
  return content.filter((block) => block.type === "text").map((block) => block.text).join("");
15076
16259
  }
16260
+ /**
16261
+ * Limit the tool list to at most `max` entries.
16262
+ * Built-in tools (those without an `mcp_server` tag) are prioritised over
16263
+ * MCP tools so core capabilities are never dropped.
16264
+ */
16265
+ limitTools(tools, max) {
16266
+ if (tools.length <= max) return tools;
16267
+ const builtin = tools.filter((t) => !("serverName" in t && t.serverName));
16268
+ const mcp = tools.filter((t) => "serverName" in t && t.serverName);
16269
+ return [...builtin, ...mcp].slice(0, max);
16270
+ }
15077
16271
  /**
15078
16272
  * Convert tools to OpenAI format
15079
16273
  */
@@ -15083,7 +16277,8 @@ var OpenAIProvider = class {
15083
16277
  function: {
15084
16278
  name: tool.name,
15085
16279
  description: truncateToolDescription(tool.description),
15086
- parameters: tool.input_schema
16280
+ parameters: tool.input_schema,
16281
+ strict: true
15087
16282
  }
15088
16283
  }));
15089
16284
  }
@@ -15177,12 +16372,12 @@ var OpenAIProvider = class {
15177
16372
  this.ensureInitialized();
15178
16373
  return withRetry(async () => {
15179
16374
  try {
15180
- const model = options?.model ?? this.config.model ?? DEFAULT_MODEL2;
16375
+ const model2 = options?.model ?? this.config.model ?? DEFAULT_MODEL2;
15181
16376
  const { input, instructions } = this.convertToResponsesInput(messages, options?.system);
15182
- const supportsTemp = this.supportsTemperature(model);
15183
- const reasoningEffort = mapToOpenAIEffort(options?.thinking, model);
16377
+ const supportsTemp = this.supportsTemperature(model2);
16378
+ const reasoningEffort = this.getResponsesReasoningEffort(model2, options?.thinking);
15184
16379
  const response = await this.client.responses.create({
15185
- model,
16380
+ model: model2,
15186
16381
  input,
15187
16382
  instructions: instructions ?? void 0,
15188
16383
  max_output_tokens: options?.maxTokens ?? this.config.maxTokens ?? 8192,
@@ -15215,13 +16410,16 @@ var OpenAIProvider = class {
15215
16410
  this.ensureInitialized();
15216
16411
  return withRetry(async () => {
15217
16412
  try {
15218
- const model = options?.model ?? this.config.model ?? DEFAULT_MODEL2;
16413
+ const model2 = options?.model ?? this.config.model ?? DEFAULT_MODEL2;
16414
+ const tierCfg = getTierConfig(this.id, model2);
15219
16415
  const { input, instructions } = this.convertToResponsesInput(messages, options?.system);
15220
- const tools = this.convertToolsForResponses(options.tools);
15221
- const supportsTemp = this.supportsTemperature(model);
15222
- const reasoningEffort = mapToOpenAIEffort(options?.thinking, model);
16416
+ const tools = this.convertToolsForResponses(
16417
+ this.limitTools(options.tools, tierCfg.maxTools)
16418
+ );
16419
+ const supportsTemp = this.supportsTemperature(model2);
16420
+ const reasoningEffort = this.getResponsesReasoningEffort(model2, options?.thinking);
15223
16421
  const response = await this.client.responses.create({
15224
- model,
16422
+ model: model2,
15225
16423
  input,
15226
16424
  instructions: instructions ?? void 0,
15227
16425
  tools,
@@ -15272,12 +16470,12 @@ var OpenAIProvider = class {
15272
16470
  this.ensureInitialized();
15273
16471
  let timeoutTriggered = false;
15274
16472
  try {
15275
- const model = options?.model ?? this.config.model ?? DEFAULT_MODEL2;
16473
+ const model2 = options?.model ?? this.config.model ?? DEFAULT_MODEL2;
15276
16474
  const { input, instructions } = this.convertToResponsesInput(messages, options?.system);
15277
- const supportsTemp = this.supportsTemperature(model);
15278
- const reasoningEffort = mapToOpenAIEffort(options?.thinking, model);
16475
+ const supportsTemp = this.supportsTemperature(model2);
16476
+ const reasoningEffort = this.getResponsesReasoningEffort(model2, options?.thinking);
15279
16477
  const stream = await this.client.responses.create({
15280
- model,
16478
+ model: model2,
15281
16479
  input,
15282
16480
  instructions: instructions ?? void 0,
15283
16481
  max_output_tokens: options?.maxTokens ?? this.config.maxTokens ?? 8192,
@@ -15336,13 +16534,15 @@ var OpenAIProvider = class {
15336
16534
  this.ensureInitialized();
15337
16535
  let timeoutTriggered = false;
15338
16536
  try {
15339
- const model = options?.model ?? this.config.model ?? DEFAULT_MODEL2;
16537
+ const model2 = options?.model ?? this.config.model ?? DEFAULT_MODEL2;
16538
+ const tierCfg = getTierConfig(this.id, model2);
15340
16539
  const { input, instructions } = this.convertToResponsesInput(messages, options?.system);
15341
- const tools = options.tools.length > 0 ? this.convertToolsForResponses(options.tools) : void 0;
15342
- const supportsTemp = this.supportsTemperature(model);
15343
- const reasoningEffort = mapToOpenAIEffort(options?.thinking, model);
16540
+ const limitedTools = this.limitTools(options.tools, tierCfg.maxTools);
16541
+ const tools = limitedTools.length > 0 ? this.convertToolsForResponses(limitedTools) : void 0;
16542
+ const supportsTemp = this.supportsTemperature(model2);
16543
+ const reasoningEffort = this.getResponsesReasoningEffort(model2, options?.thinking);
15344
16544
  const requestParams = {
15345
- model,
16545
+ model: model2,
15346
16546
  input,
15347
16547
  instructions: instructions ?? void 0,
15348
16548
  max_output_tokens: options?.maxTokens ?? this.config.maxTokens ?? 8192,
@@ -15570,7 +16770,7 @@ var OpenAIProvider = class {
15570
16770
  name: tool.name,
15571
16771
  description: tool.description ? truncateToolDescription(tool.description) : void 0,
15572
16772
  parameters: tool.input_schema ?? null,
15573
- strict: false
16773
+ strict: true
15574
16774
  }));
15575
16775
  }
15576
16776
  };
@@ -15597,8 +16797,9 @@ function createKimiProvider(config) {
15597
16797
  // src/providers/codex.ts
15598
16798
  init_errors();
15599
16799
  init_auth();
16800
+ init_catalog();
15600
16801
  var CODEX_API_ENDPOINT = "https://chatgpt.com/backend-api/codex/responses";
15601
- var DEFAULT_MODEL3 = "gpt-5.3-codex";
16802
+ var DEFAULT_MODEL3 = getCatalogDefaultModel("codex");
15602
16803
  var CONTEXT_WINDOWS3 = {
15603
16804
  "gpt-5.4-codex": 2e5,
15604
16805
  "gpt-5.3-codex": 2e5,
@@ -15665,16 +16866,23 @@ var CodexProvider = class {
15665
16866
  /**
15666
16867
  * Get context window size for a model
15667
16868
  */
15668
- getContextWindow(model) {
15669
- const m = model ?? this.config.model ?? DEFAULT_MODEL3;
15670
- return CONTEXT_WINDOWS3[m] ?? 128e3;
16869
+ getContextWindow(model2) {
16870
+ const m = model2 ?? this.config.model ?? DEFAULT_MODEL3;
16871
+ if (CONTEXT_WINDOWS3[m]) {
16872
+ return CONTEXT_WINDOWS3[m];
16873
+ }
16874
+ const catalogWindow = getCatalogContextWindow("codex", m, 0);
16875
+ if (catalogWindow > 0) {
16876
+ return catalogWindow;
16877
+ }
16878
+ return 128e3;
15671
16879
  }
15672
16880
  /**
15673
16881
  * Count tokens in text (approximate)
15674
16882
  * Uses GPT-4 approximation: ~4 chars per token
15675
16883
  */
15676
- countTokens(text) {
15677
- return Math.ceil(text.length / 4);
16884
+ countTokens(text2) {
16885
+ return Math.ceil(text2.length / 4);
15678
16886
  }
15679
16887
  /**
15680
16888
  * Check if provider is available (has valid OAuth tokens)
@@ -15802,9 +17010,9 @@ var CodexProvider = class {
15802
17010
  /**
15803
17011
  * Build the request body for the Codex Responses API
15804
17012
  */
15805
- buildRequestBody(model, input, instructions, options) {
17013
+ buildRequestBody(model2, input, instructions, options) {
15806
17014
  const body = {
15807
- model,
17015
+ model: model2,
15808
17016
  input,
15809
17017
  instructions: instructions ?? "You are a helpful coding assistant.",
15810
17018
  store: false,
@@ -15869,9 +17077,9 @@ var CodexProvider = class {
15869
17077
  */
15870
17078
  async chat(messages, options) {
15871
17079
  return withRetry(async () => {
15872
- const model = options?.model ?? this.config.model ?? DEFAULT_MODEL3;
17080
+ const model2 = options?.model ?? this.config.model ?? DEFAULT_MODEL3;
15873
17081
  const { input, instructions } = this.convertToResponsesInput(messages, options?.system);
15874
- const body = this.buildRequestBody(model, input, instructions, {
17082
+ const body = this.buildRequestBody(model2, input, instructions, {
15875
17083
  maxTokens: options?.maxTokens,
15876
17084
  temperature: options?.temperature
15877
17085
  });
@@ -15902,7 +17110,7 @@ var CodexProvider = class {
15902
17110
  id: responseId,
15903
17111
  content,
15904
17112
  stopReason,
15905
- model,
17113
+ model: model2,
15906
17114
  usage: { inputTokens, outputTokens }
15907
17115
  };
15908
17116
  }, this.retryConfig);
@@ -15912,9 +17120,9 @@ var CodexProvider = class {
15912
17120
  */
15913
17121
  async chatWithTools(messages, options) {
15914
17122
  return withRetry(async () => {
15915
- const model = options?.model ?? this.config.model ?? DEFAULT_MODEL3;
17123
+ const model2 = options?.model ?? this.config.model ?? DEFAULT_MODEL3;
15916
17124
  const { input, instructions } = this.convertToResponsesInput(messages, options?.system);
15917
- const body = this.buildRequestBody(model, input, instructions, {
17125
+ const body = this.buildRequestBody(model2, input, instructions, {
15918
17126
  tools: options.tools,
15919
17127
  maxTokens: options?.maxTokens
15920
17128
  });
@@ -15989,7 +17197,7 @@ var CodexProvider = class {
15989
17197
  id: responseId,
15990
17198
  content,
15991
17199
  stopReason: toolCalls.length > 0 ? "tool_use" : "end_turn",
15992
- model,
17200
+ model: model2,
15993
17201
  usage: { inputTokens, outputTokens },
15994
17202
  toolCalls
15995
17203
  };
@@ -15999,9 +17207,9 @@ var CodexProvider = class {
15999
17207
  * Stream a chat response (no tools)
16000
17208
  */
16001
17209
  async *stream(messages, options) {
16002
- const model = options?.model ?? this.config.model ?? DEFAULT_MODEL3;
17210
+ const model2 = options?.model ?? this.config.model ?? DEFAULT_MODEL3;
16003
17211
  const { input, instructions } = this.convertToResponsesInput(messages, options?.system);
16004
- const body = this.buildRequestBody(model, input, instructions, {
17212
+ const body = this.buildRequestBody(model2, input, instructions, {
16005
17213
  maxTokens: options?.maxTokens
16006
17214
  });
16007
17215
  const response = await this.makeRequest(body);
@@ -16061,9 +17269,9 @@ var CodexProvider = class {
16061
17269
  * item_id which references the output item's id field, not call_id.
16062
17270
  */
16063
17271
  async *streamWithTools(messages, options) {
16064
- const model = options?.model ?? this.config.model ?? DEFAULT_MODEL3;
17272
+ const model2 = options?.model ?? this.config.model ?? DEFAULT_MODEL3;
16065
17273
  const { input, instructions } = this.convertToResponsesInput(messages, options?.system);
16066
- const body = this.buildRequestBody(model, input, instructions, {
17274
+ const body = this.buildRequestBody(model2, input, instructions, {
16067
17275
  tools: options.tools,
16068
17276
  maxTokens: options?.maxTokens
16069
17277
  });
@@ -16212,6 +17420,7 @@ var CodexProvider = class {
16212
17420
  // src/providers/copilot.ts
16213
17421
  init_errors();
16214
17422
  init_copilot();
17423
+ init_catalog();
16215
17424
  var CONTEXT_WINDOWS4 = {
16216
17425
  // Claude models — Copilot API caps these at 168 000 (not 200 000 like Anthropic direct)
16217
17426
  "claude-sonnet-4.6": 168e3,
@@ -16245,10 +17454,10 @@ var CONTEXT_WINDOWS4 = {
16245
17454
  "raptor-mini": 4e5,
16246
17455
  goldeneye: 4e5
16247
17456
  };
16248
- var DEFAULT_MODEL4 = "claude-sonnet-4.6";
16249
- function normalizeModel(model) {
16250
- if (typeof model !== "string") return void 0;
16251
- const trimmed = model.trim();
17457
+ var DEFAULT_MODEL4 = getCatalogDefaultModel("copilot");
17458
+ function normalizeModel(model2) {
17459
+ if (typeof model2 !== "string") return void 0;
17460
+ const trimmed = model2.trim();
16252
17461
  return trimmed.length > 0 ? trimmed : void 0;
16253
17462
  }
16254
17463
  var COPILOT_HEADERS = {
@@ -16355,16 +17564,31 @@ var CopilotProvider = class extends OpenAIProvider {
16355
17564
  modelNeedsResponsesApi(_model) {
16356
17565
  return false;
16357
17566
  }
16358
- countTokens(text) {
16359
- if (!text) return 0;
16360
- return Math.ceil(text.length / 3.5);
17567
+ /**
17568
+ * Copilot's OpenAI-compatible endpoint currently routes through
17569
+ * Chat Completions. For GPT-5.x models, combining function tools with
17570
+ * reasoning_effort is rejected by the upstream API. Keep tools working by
17571
+ * omitting reasoning_effort on tool calls instead of advertising a broken
17572
+ * combination.
17573
+ */
17574
+ getChatCompletionsReasoningEffort(_model, _thinking, hasTools) {
17575
+ if (hasTools) return void 0;
17576
+ return void 0;
17577
+ }
17578
+ countTokens(text2) {
17579
+ if (!text2) return 0;
17580
+ return Math.ceil(text2.length / 3.5);
16361
17581
  }
16362
17582
  /**
16363
17583
  * Get context window for the current model
16364
17584
  */
16365
17585
  getContextWindow() {
16366
- const model = this.config.model ?? DEFAULT_MODEL4;
16367
- return CONTEXT_WINDOWS4[model] ?? 128e3;
17586
+ const model2 = this.config.model ?? DEFAULT_MODEL4;
17587
+ const catalogWindow = getCatalogContextWindow("copilot", model2, 0);
17588
+ if (catalogWindow > 0) {
17589
+ return catalogWindow;
17590
+ }
17591
+ return CONTEXT_WINDOWS4[model2] ?? 128e3;
16368
17592
  }
16369
17593
  /**
16370
17594
  * Check if Copilot credentials are available
@@ -16381,7 +17605,8 @@ var CopilotProvider = class extends OpenAIProvider {
16381
17605
 
16382
17606
  // src/providers/gemini.ts
16383
17607
  init_errors();
16384
- var DEFAULT_MODEL5 = "gemini-3.1-pro-preview";
17608
+ init_catalog();
17609
+ var DEFAULT_MODEL5 = getCatalogDefaultModel("gemini");
16385
17610
  var SKIP_THOUGHT_SIGNATURE_VALIDATOR = "skip_thought_signature_validator";
16386
17611
  var CONTEXT_WINDOWS5 = {
16387
17612
  "gemini-3.1-pro-preview": 1e6,
@@ -16445,9 +17670,9 @@ var GeminiProvider = class {
16445
17670
  });
16446
17671
  let streamStopReason = "end_turn";
16447
17672
  for await (const chunk of stream) {
16448
- const text = chunk.text;
16449
- if (text) {
16450
- yield { type: "text", text };
17673
+ const text2 = chunk.text;
17674
+ if (text2) {
17675
+ yield { type: "text", text: text2 };
16451
17676
  }
16452
17677
  const finishReason = chunk.candidates?.[0]?.finishReason;
16453
17678
  if (finishReason) {
@@ -16471,9 +17696,9 @@ var GeminiProvider = class {
16471
17696
  let fallbackToolCounter = 0;
16472
17697
  const emittedToolIds = /* @__PURE__ */ new Set();
16473
17698
  for await (const chunk of stream) {
16474
- const text = chunk.text;
16475
- if (text) {
16476
- yield { type: "text", text };
17699
+ const text2 = chunk.text;
17700
+ if (text2) {
17701
+ yield { type: "text", text: text2 };
16477
17702
  }
16478
17703
  const toolCalls = this.extractToolCalls(chunk, { includeLegacyFunctionCalls: true });
16479
17704
  for (const toolCall of toolCalls) {
@@ -16508,13 +17733,17 @@ var GeminiProvider = class {
16508
17733
  throw this.handleError(error);
16509
17734
  }
16510
17735
  }
16511
- countTokens(text) {
16512
- if (!text) return 0;
16513
- return Math.ceil(text.length / 3.5);
17736
+ countTokens(text2) {
17737
+ if (!text2) return 0;
17738
+ return Math.ceil(text2.length / 3.5);
16514
17739
  }
16515
17740
  getContextWindow() {
16516
- const model = this.config.model ?? DEFAULT_MODEL5;
16517
- return CONTEXT_WINDOWS5[model] ?? 1e6;
17741
+ const model2 = this.config.model ?? DEFAULT_MODEL5;
17742
+ const catalogWindow = getCatalogContextWindow("gemini", model2, 0);
17743
+ if (catalogWindow > 0) {
17744
+ return catalogWindow;
17745
+ }
17746
+ return CONTEXT_WINDOWS5[model2] ?? 1e6;
16518
17747
  }
16519
17748
  async isAvailable() {
16520
17749
  if (!this.client) return false;
@@ -16535,20 +17764,20 @@ var GeminiProvider = class {
16535
17764
  });
16536
17765
  }
16537
17766
  }
16538
- getModel(model) {
16539
- return model ?? this.config.model ?? DEFAULT_MODEL5;
17767
+ getModel(model2) {
17768
+ return model2 ?? this.config.model ?? DEFAULT_MODEL5;
16540
17769
  }
16541
17770
  buildConfig(messages, options, tools, toolChoice) {
16542
- const model = this.getModel(options?.model);
16543
- const thinkingBudget = mapToGeminiBudget(options?.thinking, model);
17771
+ const model2 = this.getModel(options?.model);
17772
+ const thinkingConfig = mapToGeminiThinkingConfig(options?.thinking, model2);
16544
17773
  const config = {
16545
17774
  maxOutputTokens: options?.maxTokens ?? this.config.maxTokens ?? 8192,
16546
17775
  temperature: options?.temperature ?? this.config.temperature ?? 0,
16547
17776
  stopSequences: options?.stopSequences,
16548
17777
  systemInstruction: this.extractSystem(messages, options?.system)
16549
17778
  };
16550
- if (thinkingBudget !== void 0) {
16551
- config.thinkingConfig = { thinkingBudget };
17779
+ if (thinkingConfig !== void 0) {
17780
+ config.thinkingConfig = thinkingConfig;
16552
17781
  }
16553
17782
  if (tools && tools.length > 0) {
16554
17783
  config.tools = [{ functionDeclarations: this.convertTools(tools) }];
@@ -16563,8 +17792,8 @@ var GeminiProvider = class {
16563
17792
  const systemMsg = messages.find((m) => m.role === "system");
16564
17793
  if (!systemMsg) return void 0;
16565
17794
  if (typeof systemMsg.content === "string") return systemMsg.content;
16566
- const text = systemMsg.content.filter((b) => b.type === "text").map((b) => b.text).join("");
16567
- return text || void 0;
17795
+ const text2 = systemMsg.content.filter((b) => b.type === "text").map((b) => b.text).join("");
17796
+ return text2 || void 0;
16568
17797
  }
16569
17798
  convertContents(messages) {
16570
17799
  const toolNameByUseId = this.buildToolUseNameMap(messages);
@@ -16687,7 +17916,7 @@ var GeminiProvider = class {
16687
17916
  })
16688
17917
  }));
16689
17918
  }
16690
- parseResponse(response, model) {
17919
+ parseResponse(response, model2) {
16691
17920
  const usage = response.usageMetadata;
16692
17921
  return {
16693
17922
  id: `gemini-${Date.now()}`,
@@ -16697,10 +17926,10 @@ var GeminiProvider = class {
16697
17926
  inputTokens: usage?.promptTokenCount ?? 0,
16698
17927
  outputTokens: usage?.candidatesTokenCount ?? 0
16699
17928
  },
16700
- model: this.getModel(model)
17929
+ model: this.getModel(model2)
16701
17930
  };
16702
17931
  }
16703
- parseResponseWithTools(response, model) {
17932
+ parseResponseWithTools(response, model2) {
16704
17933
  const usage = response.usageMetadata;
16705
17934
  const toolCalls = this.extractToolCalls(response, { includeLegacyFunctionCalls: true });
16706
17935
  return {
@@ -16711,7 +17940,7 @@ var GeminiProvider = class {
16711
17940
  inputTokens: usage?.promptTokenCount ?? 0,
16712
17941
  outputTokens: usage?.candidatesTokenCount ?? 0
16713
17942
  },
16714
- model: this.getModel(model),
17943
+ model: this.getModel(model2),
16715
17944
  toolCalls
16716
17945
  };
16717
17946
  }
@@ -16750,7 +17979,8 @@ var GeminiProvider = class {
16750
17979
  // src/providers/vertex.ts
16751
17980
  init_errors();
16752
17981
  init_gcloud();
16753
- var DEFAULT_MODEL6 = "gemini-2.5-pro";
17982
+ init_catalog();
17983
+ var DEFAULT_MODEL6 = getCatalogDefaultModel("vertex");
16754
17984
  var DEFAULT_BASE_URL = "https://aiplatform.googleapis.com/v1";
16755
17985
  var DEFAULT_LOCATION = "global";
16756
17986
  var CONTEXT_WINDOWS6 = {
@@ -16896,11 +18126,16 @@ var VertexProvider = class {
16896
18126
  }
16897
18127
  yield { type: "done", stopReason };
16898
18128
  }
16899
- countTokens(text) {
16900
- return Math.ceil(text.length / 4);
18129
+ countTokens(text2) {
18130
+ return Math.ceil(text2.length / 4);
16901
18131
  }
16902
18132
  getContextWindow() {
16903
- return CONTEXT_WINDOWS6[this.config.model ?? DEFAULT_MODEL6] ?? 1048576;
18133
+ const model2 = this.config.model ?? DEFAULT_MODEL6;
18134
+ const catalogWindow = getCatalogContextWindow("vertex", model2, 0);
18135
+ if (catalogWindow > 0) {
18136
+ return catalogWindow;
18137
+ }
18138
+ return CONTEXT_WINDOWS6[model2] ?? 1048576;
16904
18139
  }
16905
18140
  async isAvailable() {
16906
18141
  try {
@@ -16917,8 +18152,8 @@ var VertexProvider = class {
16917
18152
  });
16918
18153
  }
16919
18154
  }
16920
- getModel(model) {
16921
- return model ?? this.config.model ?? DEFAULT_MODEL6;
18155
+ getModel(model2) {
18156
+ return model2 ?? this.config.model ?? DEFAULT_MODEL6;
16922
18157
  }
16923
18158
  getResolvedBaseUrl() {
16924
18159
  if (this.config.baseUrl && this.config.baseUrl.trim()) {
@@ -16929,9 +18164,9 @@ var VertexProvider = class {
16929
18164
  }
16930
18165
  return `https://${encodeURIComponent(this.location)}-aiplatform.googleapis.com/v1`;
16931
18166
  }
16932
- buildEndpoint(model, stream = false) {
18167
+ buildEndpoint(model2, stream = false) {
16933
18168
  const action = stream ? "streamGenerateContent?alt=sse" : "generateContent";
16934
- return `${this.getResolvedBaseUrl()}/projects/${encodeURIComponent(this.project)}/locations/${encodeURIComponent(this.location)}/publishers/google/models/${encodeURIComponent(this.getModel(model))}:${action}`;
18169
+ return `${this.getResolvedBaseUrl()}/projects/${encodeURIComponent(this.project)}/locations/${encodeURIComponent(this.location)}/publishers/google/models/${encodeURIComponent(this.getModel(model2))}:${action}`;
16935
18170
  }
16936
18171
  async getHeaders() {
16937
18172
  if (this.apiKey?.trim()) {
@@ -16959,8 +18194,8 @@ var VertexProvider = class {
16959
18194
  const systemMsg = messages.find((m) => m.role === "system");
16960
18195
  if (!systemMsg) return void 0;
16961
18196
  if (typeof systemMsg.content === "string") return systemMsg.content;
16962
- const text = systemMsg.content.filter((b) => b.type === "text").map((b) => b.text).join("");
16963
- return text || void 0;
18197
+ const text2 = systemMsg.content.filter((b) => b.type === "text").map((b) => b.text).join("");
18198
+ return text2 || void 0;
16964
18199
  }
16965
18200
  buildToolUseNameMap(messages) {
16966
18201
  const map = /* @__PURE__ */ new Map();
@@ -17143,21 +18378,21 @@ var VertexProvider = class {
17143
18378
  }
17144
18379
  }
17145
18380
  }
17146
- parseResponse(response, model) {
18381
+ parseResponse(response, model2) {
17147
18382
  const candidate = response.candidates?.[0];
17148
- const text = (candidate?.content?.parts ?? []).filter((part) => part.text).map((part) => part.text).join("");
18383
+ const text2 = (candidate?.content?.parts ?? []).filter((part) => part.text).map((part) => part.text).join("");
17149
18384
  return {
17150
18385
  id: `vertex-${Date.now()}`,
17151
- content: text,
18386
+ content: text2,
17152
18387
  stopReason: this.mapFinishReason(candidate?.finishReason),
17153
18388
  usage: {
17154
18389
  inputTokens: response.usageMetadata?.promptTokenCount ?? 0,
17155
18390
  outputTokens: response.usageMetadata?.candidatesTokenCount ?? 0
17156
18391
  },
17157
- model: this.getModel(model)
18392
+ model: this.getModel(model2)
17158
18393
  };
17159
18394
  }
17160
- parseResponseWithTools(response, model) {
18395
+ parseResponseWithTools(response, model2) {
17161
18396
  const candidate = response.candidates?.[0];
17162
18397
  const parts = candidate?.content?.parts ?? [];
17163
18398
  const toolCalls = [];
@@ -17185,7 +18420,7 @@ var VertexProvider = class {
17185
18420
  inputTokens: response.usageMetadata?.promptTokenCount ?? 0,
17186
18421
  outputTokens: response.usageMetadata?.candidatesTokenCount ?? 0
17187
18422
  },
17188
- model: this.getModel(model),
18423
+ model: this.getModel(model2),
17189
18424
  toolCalls
17190
18425
  };
17191
18426
  }
@@ -17214,6 +18449,10 @@ var VertexProvider = class {
17214
18449
  }
17215
18450
  };
17216
18451
 
18452
+ // src/providers/pricing.ts
18453
+ init_catalog();
18454
+ getCatalogModelPricingMap();
18455
+
17217
18456
  // src/providers/circuit-breaker.ts
17218
18457
  init_errors();
17219
18458
  var DEFAULT_CIRCUIT_BREAKER_CONFIG = {
@@ -17419,8 +18658,8 @@ var ResilientProvider = class {
17419
18658
  async *streamWithTools(messages, options) {
17420
18659
  yield* this.streamWithPolicy(() => this.provider.streamWithTools(messages, options));
17421
18660
  }
17422
- countTokens(text) {
17423
- return this.provider.countTokens(text);
18661
+ countTokens(text2) {
18662
+ return this.provider.countTokens(text2);
17424
18663
  }
17425
18664
  getContextWindow() {
17426
18665
  return this.provider.getContextWindow();
@@ -17506,13 +18745,16 @@ function createResilientProvider(provider, config) {
17506
18745
  return new ResilientProvider(provider, getDefaultResilienceConfig(provider.id));
17507
18746
  }
17508
18747
 
18748
+ // src/providers/runtime-capabilities.ts
18749
+ init_catalog();
18750
+
17509
18751
  // src/providers/index.ts
17510
18752
  init_copilot();
17511
18753
  init_errors();
17512
18754
  init_env();
17513
- function normalizeProviderModel(model) {
17514
- if (typeof model !== "string") return void 0;
17515
- const trimmed = model.trim();
18755
+ function normalizeProviderModel(model2) {
18756
+ if (typeof model2 !== "string") return void 0;
18757
+ const trimmed = model2.trim();
17516
18758
  return trimmed.length > 0 ? trimmed : void 0;
17517
18759
  }
17518
18760
  function normalizeOptional(value) {
@@ -17721,9 +18963,9 @@ function createInitialState(config) {
17721
18963
  }
17722
18964
  async function loadExistingState(projectPath) {
17723
18965
  try {
17724
- const fs39 = await import('fs/promises');
18966
+ const fs41 = await import('fs/promises');
17725
18967
  const statePath = `${projectPath}/.coco/state/project.json`;
17726
- const content = await fs39.readFile(statePath, "utf-8");
18968
+ const content = await fs41.readFile(statePath, "utf-8");
17727
18969
  const data = JSON.parse(content);
17728
18970
  data.createdAt = new Date(data.createdAt);
17729
18971
  data.updatedAt = new Date(data.updatedAt);
@@ -17733,13 +18975,13 @@ async function loadExistingState(projectPath) {
17733
18975
  }
17734
18976
  }
17735
18977
  async function saveState(state) {
17736
- const fs39 = await import('fs/promises');
18978
+ const fs41 = await import('fs/promises');
17737
18979
  const statePath = `${state.path}/.coco/state`;
17738
- await fs39.mkdir(statePath, { recursive: true });
18980
+ await fs41.mkdir(statePath, { recursive: true });
17739
18981
  const filePath = `${statePath}/project.json`;
17740
18982
  const tmpPath = `${filePath}.tmp.${Date.now()}`;
17741
- await fs39.writeFile(tmpPath, JSON.stringify(state, null, 2), "utf-8");
17742
- await fs39.rename(tmpPath, filePath);
18983
+ await fs41.writeFile(tmpPath, JSON.stringify(state, null, 2), "utf-8");
18984
+ await fs41.rename(tmpPath, filePath);
17743
18985
  }
17744
18986
  function getPhaseExecutor(phase) {
17745
18987
  switch (phase) {
@@ -17798,35 +19040,35 @@ async function createPhaseContext(config, state) {
17798
19040
  };
17799
19041
  const tools = {
17800
19042
  file: {
17801
- async read(path42) {
17802
- const fs39 = await import('fs/promises');
17803
- return fs39.readFile(path42, "utf-8");
19043
+ async read(path44) {
19044
+ const fs41 = await import('fs/promises');
19045
+ return fs41.readFile(path44, "utf-8");
17804
19046
  },
17805
- async write(path42, content) {
17806
- const fs39 = await import('fs/promises');
19047
+ async write(path44, content) {
19048
+ const fs41 = await import('fs/promises');
17807
19049
  const nodePath = await import('path');
17808
- await fs39.mkdir(nodePath.dirname(path42), { recursive: true });
17809
- await fs39.writeFile(path42, content, "utf-8");
19050
+ await fs41.mkdir(nodePath.dirname(path44), { recursive: true });
19051
+ await fs41.writeFile(path44, content, "utf-8");
17810
19052
  },
17811
- async exists(path42) {
17812
- const fs39 = await import('fs/promises');
19053
+ async exists(path44) {
19054
+ const fs41 = await import('fs/promises');
17813
19055
  try {
17814
- await fs39.access(path42);
19056
+ await fs41.access(path44);
17815
19057
  return true;
17816
19058
  } catch {
17817
19059
  return false;
17818
19060
  }
17819
19061
  },
17820
19062
  async glob(pattern) {
17821
- const { glob: glob17 } = await import('glob');
17822
- return glob17(pattern, { cwd: state.path });
19063
+ const { glob: glob18 } = await import('glob');
19064
+ return glob18(pattern, { cwd: state.path });
17823
19065
  }
17824
19066
  },
17825
19067
  bash: {
17826
19068
  async exec(command, options = {}) {
17827
- const { execa: execa11 } = await import('execa');
19069
+ const { execa: execa12 } = await import('execa');
17828
19070
  try {
17829
- const result = await execa11(command, {
19071
+ const result = await execa12(command, {
17830
19072
  shell: true,
17831
19073
  cwd: options.cwd || state.path,
17832
19074
  timeout: options.timeout,
@@ -17849,8 +19091,8 @@ async function createPhaseContext(config, state) {
17849
19091
  },
17850
19092
  git: {
17851
19093
  async status() {
17852
- const { execa: execa11 } = await import('execa');
17853
- const result = await execa11("git", ["status", "--porcelain", "-b"], { cwd: state.path });
19094
+ const { execa: execa12 } = await import('execa');
19095
+ const result = await execa12("git", ["status", "--porcelain", "-b"], { cwd: state.path });
17854
19096
  const lines = result.stdout.split("\n");
17855
19097
  const branchLine = lines[0] || "";
17856
19098
  const branch = branchLine.replace("## ", "").split("...")[0] || "main";
@@ -17863,24 +19105,24 @@ async function createPhaseContext(config, state) {
17863
19105
  };
17864
19106
  },
17865
19107
  async commit(message, files) {
17866
- const { execa: execa11 } = await import('execa');
19108
+ const { execa: execa12 } = await import('execa');
17867
19109
  if (files && files.length > 0) {
17868
- await execa11("git", ["add", ...files], { cwd: state.path });
19110
+ await execa12("git", ["add", ...files], { cwd: state.path });
17869
19111
  }
17870
- await execa11("git", ["commit", "-m", message], { cwd: state.path });
19112
+ await execa12("git", ["commit", "-m", message], { cwd: state.path });
17871
19113
  },
17872
19114
  async push() {
17873
- const { execa: execa11 } = await import('execa');
17874
- await execa11("git", ["push"], { cwd: state.path });
19115
+ const { execa: execa12 } = await import('execa');
19116
+ await execa12("git", ["push"], { cwd: state.path });
17875
19117
  }
17876
19118
  },
17877
19119
  test: {
17878
19120
  async run(pattern) {
17879
- const { execa: execa11 } = await import('execa');
19121
+ const { execa: execa12 } = await import('execa');
17880
19122
  try {
17881
19123
  const args = ["test", "--reporter=json"];
17882
19124
  if (pattern) args.push(pattern);
17883
- await execa11("pnpm", args, { cwd: state.path });
19125
+ await execa12("pnpm", args, { cwd: state.path });
17884
19126
  return {
17885
19127
  passed: 0,
17886
19128
  failed: 0,
@@ -17960,9 +19202,9 @@ async function createSnapshot(state) {
17960
19202
  var MAX_CHECKPOINT_VERSIONS = 5;
17961
19203
  async function getCheckpointFiles(state, phase) {
17962
19204
  try {
17963
- const fs39 = await import('fs/promises');
19205
+ const fs41 = await import('fs/promises');
17964
19206
  const checkpointDir = `${state.path}/.coco/checkpoints`;
17965
- const files = await fs39.readdir(checkpointDir);
19207
+ const files = await fs41.readdir(checkpointDir);
17966
19208
  const phaseFiles = files.filter((f) => f.startsWith(`snapshot-pre-${phase}-`) && f.endsWith(".json")).sort((a, b) => {
17967
19209
  const tsA = parseInt(a.split("-").pop()?.replace(".json", "") ?? "0", 10);
17968
19210
  const tsB = parseInt(b.split("-").pop()?.replace(".json", "") ?? "0", 10);
@@ -17975,11 +19217,11 @@ async function getCheckpointFiles(state, phase) {
17975
19217
  }
17976
19218
  async function cleanupOldCheckpoints(state, phase) {
17977
19219
  try {
17978
- const fs39 = await import('fs/promises');
19220
+ const fs41 = await import('fs/promises');
17979
19221
  const files = await getCheckpointFiles(state, phase);
17980
19222
  if (files.length > MAX_CHECKPOINT_VERSIONS) {
17981
19223
  const filesToDelete = files.slice(MAX_CHECKPOINT_VERSIONS);
17982
- await Promise.all(filesToDelete.map((f) => fs39.unlink(f).catch(() => {
19224
+ await Promise.all(filesToDelete.map((f) => fs41.unlink(f).catch(() => {
17983
19225
  })));
17984
19226
  }
17985
19227
  } catch {
@@ -17987,13 +19229,13 @@ async function cleanupOldCheckpoints(state, phase) {
17987
19229
  }
17988
19230
  async function saveSnapshot(state, snapshotId) {
17989
19231
  try {
17990
- const fs39 = await import('fs/promises');
19232
+ const fs41 = await import('fs/promises');
17991
19233
  const snapshotPath = `${state.path}/.coco/checkpoints/snapshot-${snapshotId}.json`;
17992
19234
  const snapshotDir = `${state.path}/.coco/checkpoints`;
17993
- await fs39.mkdir(snapshotDir, { recursive: true });
19235
+ await fs41.mkdir(snapshotDir, { recursive: true });
17994
19236
  const createdAt = state.createdAt instanceof Date ? state.createdAt.toISOString() : String(state.createdAt);
17995
19237
  const updatedAt = state.updatedAt instanceof Date ? state.updatedAt.toISOString() : String(state.updatedAt);
17996
- await fs39.writeFile(
19238
+ await fs41.writeFile(
17997
19239
  snapshotPath,
17998
19240
  JSON.stringify(
17999
19241
  {
@@ -18422,7 +19664,7 @@ Use list_dir or glob to find the correct path.`;
18422
19664
  }
18423
19665
  var readFileTool = defineTool({
18424
19666
  name: "read_file",
18425
- description: `Read the contents of a file.
19667
+ description: `Read the full text content of a file at the given path and return it as a string. Use this when you need the actual source code, configuration values, or text content of a specific file you already know the path to. Do NOT use this to list files in a directory (use list_directory), to check if a file exists (use file_exists), or to search for files by name pattern (use find_files). Returns an error if the path does not exist or is not a readable text file.
18426
19668
 
18427
19669
  Examples:
18428
19670
  - Read config: { "path": "package.json" }
@@ -18480,7 +19722,7 @@ Examples:
18480
19722
  });
18481
19723
  var writeFileTool = defineTool({
18482
19724
  name: "write_file",
18483
- description: `Write content to a file, creating it if it doesn't exist.
19725
+ description: `Write text content to a file, replacing it entirely if it already exists or creating it if it does not. Use this when you want to create a new file or fully replace an existing file's content. Do NOT use this to make a small change to an existing file (use edit_file instead, which performs a targeted find-and-replace without rewriting the whole file). Set createDirs: true to automatically create missing parent directories; otherwise the parent directory must already exist.
18484
19726
 
18485
19727
  Examples:
18486
19728
  - Create file: { "path": "src/utils.ts", "content": "export const foo = 1;" }
@@ -18541,7 +19783,7 @@ Examples:
18541
19783
  });
18542
19784
  var editFileTool = defineTool({
18543
19785
  name: "edit_file",
18544
- description: `Edit a file by replacing text (find and replace).
19786
+ description: `Make a targeted text replacement inside an existing file by finding oldText and replacing it with newText. Use this for surgical edits to source code, configuration files, or documentation \u2014 it is much safer than rewriting the whole file with write_file because it only touches the exact bytes you specify. The oldText must match exactly (including whitespace and indentation); if it appears more than once in the file, use all: true to replace every occurrence or make oldText longer to be unique. Do NOT use this to create new files (use write_file) or to rename/move files (use move_path).
18545
19787
 
18546
19788
  Examples:
18547
19789
  - Single replace: { "path": "src/app.ts", "oldText": "TODO:", "newText": "DONE:" }
@@ -18625,7 +19867,7 @@ Hint: Use read_file first to verify the exact content.`
18625
19867
  });
18626
19868
  var globTool = defineTool({
18627
19869
  name: "glob",
18628
- description: `Find files matching a glob pattern.
19870
+ description: `Find files whose paths match a glob pattern and return their relative paths as a list. Use this when you know the file extension or naming convention but not the exact path (e.g. find all TypeScript test files, all JSON configs). Do NOT use this to search inside file contents \u2014 use grep or search for that. Returns an empty list when nothing matches; does not throw an error for zero results. node_modules, .git, and dist directories are excluded by default.
18629
19871
 
18630
19872
  Examples:
18631
19873
  - All TypeScript: { "pattern": "**/*.ts" }
@@ -18667,7 +19909,7 @@ Examples:
18667
19909
  });
18668
19910
  var fileExistsTool = defineTool({
18669
19911
  name: "file_exists",
18670
- description: `Check if a file or directory exists.
19912
+ description: `Check whether a path exists on disk and whether it is a file or directory. Use this before attempting to read or write a path when you are unsure it exists \u2014 it never throws, always returning { exists: false } for missing paths. Do NOT use this to read file contents (use read_file) or to list directory contents (use list_directory). Returns isFile and isDirectory flags so you can distinguish files from directories in a single call.
18671
19913
 
18672
19914
  Examples:
18673
19915
  - Check file: { "path": "package.json" } \u2192 { "exists": true, "isFile": true, "isDirectory": false }
@@ -18697,7 +19939,7 @@ Examples:
18697
19939
  });
18698
19940
  var listDirTool = defineTool({
18699
19941
  name: "list_dir",
18700
- description: `List contents of a directory.
19942
+ description: `List the immediate entries (files and subdirectories) inside a directory and return their names, types, and sizes. Use this to understand what's in a folder before deciding which files to read. Do NOT use this to find files matching a pattern across the whole project (use glob) or to read file contents (use read_file). Returns an error if the path does not exist or is not a directory.
18701
19943
 
18702
19944
  Examples:
18703
19945
  - List src: { "path": "src" }
@@ -19130,16 +20372,11 @@ var SENSITIVE_ENV_PATTERNS = [
19130
20372
  ];
19131
20373
  var bashExecTool = defineTool({
19132
20374
  name: "bash_exec",
19133
- description: `Execute a bash/shell command in the user's shell environment.
20375
+ description: `Execute a shell command and return its stdout, stderr, and exit code. Use this for running build scripts, test runners, linters, package managers, CLI tools, git commands, or any other shell operation. Runs in the user's shell environment with their full PATH and locally-configured credentials (kubeconfig, gcloud auth, AWS profiles, SSH keys) so never claim you cannot run a command due to missing credentials \u2014 always attempt and report the actual exit code. Do NOT use this to read or write files (use read_file / write_file / edit_file which are safer); prefer specific file tools for file operations.
19134
20376
 
19135
20377
  Runs with the user's full PATH and inherited environment \u2014 any tool installed
19136
20378
  on the user's machine is available: kubectl, gcloud, aws, docker, git, node,
19137
- pnpm, and others. Credentials configured locally are inherited automatically:
19138
- kubeconfig contexts, gcloud auth, AWS profiles, SSH keys, etc.
19139
-
19140
- IMPORTANT: never claim you cannot run a command because you lack credentials
19141
- or access \u2014 the environment is the user's own shell. Always attempt; report
19142
- failure only if the command actually returns a non-zero exit code.
20379
+ pnpm, and others.
19143
20380
 
19144
20381
  Examples:
19145
20382
  - List files: { "command": "ls -la" }
@@ -19205,15 +20442,15 @@ ${message}
19205
20442
  let stdoutBuffer = "";
19206
20443
  let stderrBuffer = "";
19207
20444
  subprocess.stdout?.on("data", (chunk) => {
19208
- const text = chunk.toString();
19209
- stdoutBuffer += text;
19210
- process.stdout.write(text);
20445
+ const text2 = chunk.toString();
20446
+ stdoutBuffer += text2;
20447
+ process.stdout.write(text2);
19211
20448
  heartbeat.activity();
19212
20449
  });
19213
20450
  subprocess.stderr?.on("data", (chunk) => {
19214
- const text = chunk.toString();
19215
- stderrBuffer += text;
19216
- process.stderr.write(text);
20451
+ const text2 = chunk.toString();
20452
+ stderrBuffer += text2;
20453
+ process.stderr.write(text2);
19217
20454
  heartbeat.activity();
19218
20455
  });
19219
20456
  const result = await subprocess;
@@ -19408,7 +20645,7 @@ function getGit(cwd) {
19408
20645
  }
19409
20646
  var gitStatusTool = defineTool({
19410
20647
  name: "git_status",
19411
- description: `Get the current git repository status including branch, staged, modified, and untracked files.
20648
+ description: `Return the current git repository state: branch name, staged files, modified files, and untracked files. Use this before committing to see what has changed, or to check which branch is active. Do NOT use this to see the content of changes (use git_diff), or to view history (use git_log). Returns isClean: true when the working tree is clean with nothing to commit.
19412
20649
 
19413
20650
  Examples:
19414
20651
  - Current dir: {} \u2192 { "branch": "main", "isClean": false, "modified": ["src/app.ts"] }
@@ -19442,7 +20679,7 @@ Examples:
19442
20679
  });
19443
20680
  var gitDiffTool = defineTool({
19444
20681
  name: "git_diff",
19445
- description: `Get git diff showing file changes.
20682
+ description: `Show the unified diff of changes in the working tree or staging area. Use this to see exactly what lines changed in files before committing, or to review changes the user just made. Use staged: true to see only what has been staged (git add), or omit it to see all unstaged changes. Do NOT use this to see commit history (use git_log) or file status summary (use git_status).
19446
20683
 
19447
20684
  Examples:
19448
20685
  - All changes: {} \u2192 { "diff": "...", "filesChanged": 3, "insertions": 42, "deletions": 10 }
@@ -19479,7 +20716,7 @@ Examples:
19479
20716
  });
19480
20717
  var gitAddTool = defineTool({
19481
20718
  name: "git_add",
19482
- description: `Stage files for commit.
20719
+ description: `Stage one or more files (or patterns) so they are included in the next git commit. Use this after making file edits to mark them ready for commit. Pass ["."] to stage all changes, or list specific file paths to stage selectively. Do NOT use this to commit (use git_commit after staging) or to view what is staged (use git_status or git_diff with staged: true).
19483
20720
 
19484
20721
  Examples:
19485
20722
  - Stage all: { "files": ["."] }
@@ -19505,7 +20742,7 @@ Examples:
19505
20742
  });
19506
20743
  var gitCommitTool = defineTool({
19507
20744
  name: "git_commit",
19508
- description: `Create a git commit with the staged changes.
20745
+ description: `Create a git commit from whatever is currently staged (git add must run first). Use conventional commit format (feat/fix/docs/chore). Do NOT use this when nothing is staged \u2014 check git_status first; do NOT use this to stage files (use git_add) or to see what will be committed (use git_diff with staged: true).
19509
20746
 
19510
20747
  Examples:
19511
20748
  - Simple commit: { "message": "fix: resolve auth bug" }
@@ -19538,7 +20775,7 @@ Examples:
19538
20775
  });
19539
20776
  var gitLogTool = defineTool({
19540
20777
  name: "git_log",
19541
- description: `Get git commit history.
20778
+ description: `Show git commit history with hashes, messages, authors, and dates. Use this to understand what changed recently, find the commit that introduced a bug, or check whether a feature was already merged. Do NOT use this to see the content of changes \u2014 use git_diff; do NOT use this to check current file state \u2014 use git_status.
19542
20779
 
19543
20780
  Examples:
19544
20781
  - Last 10 commits: {} (default)
@@ -19578,7 +20815,7 @@ Examples:
19578
20815
  });
19579
20816
  var gitBranchTool = defineTool({
19580
20817
  name: "git_branch",
19581
- description: `Manage git branches (list, create, delete).
20818
+ description: `List all local branches, create a new branch from the current HEAD, or delete a branch. Use this to see available branches before checking out, or to create a feature branch. Do NOT use this to switch the active branch \u2014 use git_checkout; do NOT delete branches that have unmerged work.
19582
20819
 
19583
20820
  Examples:
19584
20821
  - List branches: {} \u2192 { "branches": ["main", "feature/x"], "current": "main" }
@@ -19622,7 +20859,7 @@ Examples:
19622
20859
  });
19623
20860
  var gitCheckoutTool = defineTool({
19624
20861
  name: "git_checkout",
19625
- description: `Switch branches or create and switch to a new branch.
20862
+ description: `Switch the working directory to an existing branch, or create a new branch and switch to it in one step. Use this to move between branches or start a new feature branch. Do NOT use this with unsaved file edits (stage or stash first); do NOT use this to just list branches \u2014 use git_branch.
19626
20863
 
19627
20864
  Examples:
19628
20865
  - Switch branch: { "branch": "main" }
@@ -19652,7 +20889,7 @@ Examples:
19652
20889
  });
19653
20890
  var gitPushTool = defineTool({
19654
20891
  name: "git_push",
19655
- description: `Push commits to remote repository.
20892
+ description: `Upload local commits to a remote repository. Use setUpstream: true the first time you push a new branch to create the tracking relationship. Do NOT use this on main/master without explicit user confirmation \u2014 it modifies shared history; do NOT push without first checking git_status to confirm all commits are clean.
19656
20893
 
19657
20894
  Examples:
19658
20895
  - Push current: {} \u2192 pushes to origin
@@ -19690,7 +20927,7 @@ Examples:
19690
20927
  });
19691
20928
  var gitPullTool = defineTool({
19692
20929
  name: "git_pull",
19693
- description: `Pull changes from remote repository.
20930
+ description: `Fetch and integrate remote commits into the current branch. Use rebase: true to keep a linear history (preferred for feature branches). Do NOT use this when you have uncommitted local changes \u2014 stage or stash them first; if a merge conflict is reported, use read_file / edit_file to resolve then git_add and git_commit.
19694
20931
 
19695
20932
  Examples:
19696
20933
  - Pull current: {} \u2192 pulls from origin
@@ -20698,7 +21935,7 @@ Examples:
20698
21935
  }
20699
21936
  });
20700
21937
  async function findSourceFiles(cwd) {
20701
- const { glob: glob17 } = await import('glob');
21938
+ const { glob: glob18 } = await import('glob');
20702
21939
  let isJava = false;
20703
21940
  try {
20704
21941
  await fs16__default.access(path17__default.join(cwd, "pom.xml"));
@@ -20716,12 +21953,12 @@ async function findSourceFiles(cwd) {
20716
21953
  }
20717
21954
  }
20718
21955
  if (isJava) {
20719
- return glob17("src/main/java/**/*.java", {
21956
+ return glob18("src/main/java/**/*.java", {
20720
21957
  cwd,
20721
21958
  absolute: true
20722
21959
  });
20723
21960
  }
20724
- return glob17("src/**/*.{ts,js,tsx,jsx}", {
21961
+ return glob18("src/**/*.{ts,js,tsx,jsx}", {
20725
21962
  cwd,
20726
21963
  absolute: true,
20727
21964
  ignore: ["**/*.test.*", "**/*.spec.*", "**/node_modules/**"]
@@ -20813,7 +22050,7 @@ var qualityTools = [runLinterTool, analyzeComplexityTool, calculateQualityTool];
20813
22050
  init_errors();
20814
22051
  var grepTool = defineTool({
20815
22052
  name: "grep",
20816
- description: `Search for text patterns in files using regex.
22053
+ description: `Search for a regex pattern across all files in a directory and return matching lines with file paths and line numbers. Use this when you know a symbol name, string literal, or pattern and want to find where it appears in the codebase (function definitions, imports, error messages, config keys). Do NOT use this to find files by name \u2014 use glob for that. Do NOT use this when you already know the file path \u2014 use read_file directly. Searches are recursive by default; narrow with the include glob to restrict to specific file types.
20817
22054
 
20818
22055
  Examples:
20819
22056
  - Simple search: { "pattern": "TODO" }
@@ -20946,7 +22183,7 @@ Examples:
20946
22183
  });
20947
22184
  var findInFileTool = defineTool({
20948
22185
  name: "find_in_file",
20949
- description: `Search for a pattern in a single file.
22186
+ description: `Search for a text or regex pattern inside a single known file and return matching line numbers and content. Use this when you already have the file path and want to quickly find which lines match (e.g. locate a function signature, find an import, or confirm a value exists). Do NOT use this to search across the whole project \u2014 use grep for that. Returns line numbers so you can navigate directly to the match.
20950
22187
 
20951
22188
  Examples:
20952
22189
  - Find text: { "file": "src/app.ts", "pattern": "export" }
@@ -21234,15 +22471,15 @@ ${message}
21234
22471
  let stdoutBuffer = "";
21235
22472
  let stderrBuffer = "";
21236
22473
  subprocess.stdout?.on("data", (chunk) => {
21237
- const text = chunk.toString();
21238
- stdoutBuffer += text;
21239
- process.stdout.write(text);
22474
+ const text2 = chunk.toString();
22475
+ stdoutBuffer += text2;
22476
+ process.stdout.write(text2);
21240
22477
  heartbeat.activity();
21241
22478
  });
21242
22479
  subprocess.stderr?.on("data", (chunk) => {
21243
- const text = chunk.toString();
21244
- stderrBuffer += text;
21245
- process.stderr.write(text);
22480
+ const text2 = chunk.toString();
22481
+ stderrBuffer += text2;
22482
+ process.stderr.write(text2);
21246
22483
  heartbeat.activity();
21247
22484
  });
21248
22485
  const result = await subprocess;
@@ -21359,15 +22596,15 @@ ${message}
21359
22596
  let stdoutBuffer = "";
21360
22597
  let stderrBuffer = "";
21361
22598
  subprocess.stdout?.on("data", (chunk) => {
21362
- const text = chunk.toString();
21363
- stdoutBuffer += text;
21364
- process.stdout.write(text);
22599
+ const text2 = chunk.toString();
22600
+ stdoutBuffer += text2;
22601
+ process.stdout.write(text2);
21365
22602
  heartbeat.activity();
21366
22603
  });
21367
22604
  subprocess.stderr?.on("data", (chunk) => {
21368
- const text = chunk.toString();
21369
- stderrBuffer += text;
21370
- process.stderr.write(text);
22605
+ const text2 = chunk.toString();
22606
+ stderrBuffer += text2;
22607
+ process.stderr.write(text2);
21371
22608
  heartbeat.activity();
21372
22609
  });
21373
22610
  const result = await subprocess;
@@ -21461,15 +22698,15 @@ ${message}
21461
22698
  let stdoutBuffer = "";
21462
22699
  let stderrBuffer = "";
21463
22700
  subprocess.stdout?.on("data", (chunk) => {
21464
- const text = chunk.toString();
21465
- stdoutBuffer += text;
21466
- process.stdout.write(text);
22701
+ const text2 = chunk.toString();
22702
+ stdoutBuffer += text2;
22703
+ process.stdout.write(text2);
21467
22704
  heartbeat.activity();
21468
22705
  });
21469
22706
  subprocess.stderr?.on("data", (chunk) => {
21470
- const text = chunk.toString();
21471
- stderrBuffer += text;
21472
- process.stderr.write(text);
22707
+ const text2 = chunk.toString();
22708
+ stderrBuffer += text2;
22709
+ process.stderr.write(text2);
21473
22710
  heartbeat.activity();
21474
22711
  });
21475
22712
  const result = await subprocess;
@@ -21564,15 +22801,15 @@ ${message}
21564
22801
  let stdoutBuffer = "";
21565
22802
  let stderrBuffer = "";
21566
22803
  subprocess.stdout?.on("data", (chunk) => {
21567
- const text = chunk.toString();
21568
- stdoutBuffer += text;
21569
- process.stdout.write(text);
22804
+ const text2 = chunk.toString();
22805
+ stdoutBuffer += text2;
22806
+ process.stdout.write(text2);
21570
22807
  heartbeat.activity();
21571
22808
  });
21572
22809
  subprocess.stderr?.on("data", (chunk) => {
21573
- const text = chunk.toString();
21574
- stderrBuffer += text;
21575
- process.stderr.write(text);
22810
+ const text2 = chunk.toString();
22811
+ stderrBuffer += text2;
22812
+ process.stderr.write(text2);
21576
22813
  heartbeat.activity();
21577
22814
  });
21578
22815
  const result = await subprocess;
@@ -21668,15 +22905,15 @@ ${message}
21668
22905
  let stdoutBuffer = "";
21669
22906
  let stderrBuffer = "";
21670
22907
  subprocess.stdout?.on("data", (chunk) => {
21671
- const text = chunk.toString();
21672
- stdoutBuffer += text;
21673
- process.stdout.write(text);
22908
+ const text2 = chunk.toString();
22909
+ stdoutBuffer += text2;
22910
+ process.stdout.write(text2);
21674
22911
  heartbeat.activity();
21675
22912
  });
21676
22913
  subprocess.stderr?.on("data", (chunk) => {
21677
- const text = chunk.toString();
21678
- stderrBuffer += text;
21679
- process.stderr.write(text);
22914
+ const text2 = chunk.toString();
22915
+ stderrBuffer += text2;
22916
+ process.stderr.write(text2);
21680
22917
  heartbeat.activity();
21681
22918
  });
21682
22919
  const result = await subprocess;
@@ -21755,15 +22992,15 @@ ${message}
21755
22992
  let stdoutBuffer = "";
21756
22993
  let stderrBuffer = "";
21757
22994
  subprocess.stdout?.on("data", (chunk) => {
21758
- const text = chunk.toString();
21759
- stdoutBuffer += text;
21760
- process.stdout.write(text);
22995
+ const text2 = chunk.toString();
22996
+ stdoutBuffer += text2;
22997
+ process.stdout.write(text2);
21761
22998
  heartbeat.activity();
21762
22999
  });
21763
23000
  subprocess.stderr?.on("data", (chunk) => {
21764
- const text = chunk.toString();
21765
- stderrBuffer += text;
21766
- process.stderr.write(text);
23001
+ const text2 = chunk.toString();
23002
+ stderrBuffer += text2;
23003
+ process.stderr.write(text2);
21767
23004
  heartbeat.activity();
21768
23005
  });
21769
23006
  const result = await subprocess;
@@ -21822,6 +23059,12 @@ z.object({
21822
23059
  "allowed-tools": z.union([z.string(), z.array(z.string())]).optional(),
21823
23060
  "argument-hint": z.string().optional(),
21824
23061
  compatibility: z.string().max(500).optional(),
23062
+ triggers: z.union([z.string(), z.array(z.string())]).optional(),
23063
+ risk: z.enum(["read-only", "write", "network", "destructive", "secrets-sensitive"]).optional(),
23064
+ "supported-agents": z.union([
23065
+ z.enum(["coco", "claude", "codex", "gemini", "opencode"]),
23066
+ z.array(z.enum(["coco", "claude", "codex", "gemini", "opencode"]))
23067
+ ]).optional(),
21825
23068
  model: z.string().optional(),
21826
23069
  context: z.enum(["fork", "agent", "inline"]).optional(),
21827
23070
  // Top-level tags/author (skills.sh style) — also accepted inside metadata
@@ -22447,7 +23690,7 @@ async function searchSerpApi(query, maxResults, timeout) {
22447
23690
  }
22448
23691
  var webSearchTool = defineTool({
22449
23692
  name: "web_search",
22450
- description: `Search the web for information, documentation, error solutions, and API references.
23693
+ description: `Search the web using a natural-language query and return a list of result titles, URLs, and short excerpts. Use this when you need to find documentation, research an error message, discover API references, or learn about a library before you have a specific URL. Do NOT use this when you already have the URL \u2014 use web_fetch to read a known page directly. Returns result titles and URLs you can then fetch with web_fetch for full content.
22451
23694
 
22452
23695
  Examples:
22453
23696
  - Basic search: { "query": "typescript zod validation examples" }
@@ -22624,16 +23867,16 @@ function htmlToMarkdown(html) {
22624
23867
  const prefix = "#".repeat(i);
22625
23868
  const regex = new RegExp(`<h${i}[^>]*>([\\s\\S]*?)<\\/h${i}>`, "gi");
22626
23869
  md = md.replace(regex, (_, content) => {
22627
- const text = content.replace(/<[^>]*>/g, "").trim();
22628
- return text ? `
23870
+ const text2 = content.replace(/<[^>]*>/g, "").trim();
23871
+ return text2 ? `
22629
23872
 
22630
- ${prefix} ${text}
23873
+ ${prefix} ${text2}
22631
23874
 
22632
23875
  ` : "";
22633
23876
  });
22634
23877
  }
22635
- md = md.replace(/<a\s+[^>]*href=["']([^"']+)["'][^>]*>([\s\S]*?)<\/a>/gi, (_, href, text) => {
22636
- const cleanText = text.replace(/<[^>]*>/g, "").trim();
23878
+ md = md.replace(/<a\s+[^>]*href=["']([^"']+)["'][^>]*>([\s\S]*?)<\/a>/gi, (_, href, text2) => {
23879
+ const cleanText = text2.replace(/<[^>]*>/g, "").trim();
22637
23880
  if (!cleanText) return "";
22638
23881
  if (href.startsWith("#") || href.startsWith("javascript:")) return cleanText;
22639
23882
  return `[${cleanText}](${href})`;
@@ -22660,8 +23903,8 @@ ${decoded.trim()}
22660
23903
  });
22661
23904
  md = md.replace(/<ul[^>]*>([\s\S]*?)<\/ul>/gi, (_, items) => {
22662
23905
  return "\n" + items.replace(/<li[^>]*>([\s\S]*?)<\/li>/gi, (_2, item) => {
22663
- const text = item.replace(/<[^>]*>/g, "").trim();
22664
- return text ? `- ${text}
23906
+ const text2 = item.replace(/<[^>]*>/g, "").trim();
23907
+ return text2 ? `- ${text2}
22665
23908
  ` : "";
22666
23909
  }) + "\n";
22667
23910
  });
@@ -22669,29 +23912,29 @@ ${decoded.trim()}
22669
23912
  let counter = 0;
22670
23913
  return "\n" + items.replace(/<li[^>]*>([\s\S]*?)<\/li>/gi, (_2, item) => {
22671
23914
  counter++;
22672
- const text = item.replace(/<[^>]*>/g, "").trim();
22673
- return text ? `${counter}. ${text}
23915
+ const text2 = item.replace(/<[^>]*>/g, "").trim();
23916
+ return text2 ? `${counter}. ${text2}
22674
23917
  ` : "";
22675
23918
  }) + "\n";
22676
23919
  });
22677
23920
  md = md.replace(/<blockquote[^>]*>([\s\S]*?)<\/blockquote>/gi, (_, content) => {
22678
- const text = content.replace(/<[^>]*>/g, "").trim();
22679
- return text ? "\n" + text.split("\n").map((line) => `> ${line.trim()}`).join("\n") + "\n" : "";
23921
+ const text2 = content.replace(/<[^>]*>/g, "").trim();
23922
+ return text2 ? "\n" + text2.split("\n").map((line) => `> ${line.trim()}`).join("\n") + "\n" : "";
22680
23923
  });
22681
23924
  md = md.replace(/<p[^>]*>([\s\S]*?)<\/p>/gi, (_, content) => {
22682
- const text = content.replace(/<[^>]*>/g, "").trim();
22683
- return text ? `
23925
+ const text2 = content.replace(/<[^>]*>/g, "").trim();
23926
+ return text2 ? `
22684
23927
 
22685
- ${text}
23928
+ ${text2}
22686
23929
 
22687
23930
  ` : "";
22688
23931
  });
22689
23932
  md = md.replace(/<br\s*\/?>/gi, "\n");
22690
23933
  md = md.replace(
22691
23934
  /<(?:strong|b)[^>]*>([\s\S]*?)<\/(?:strong|b)>/gi,
22692
- (_, text) => `**${text.trim()}**`
23935
+ (_, text2) => `**${text2.trim()}**`
22693
23936
  );
22694
- md = md.replace(/<(?:em|i)[^>]*>([\s\S]*?)<\/(?:em|i)>/gi, (_, text) => `*${text.trim()}*`);
23937
+ md = md.replace(/<(?:em|i)[^>]*>([\s\S]*?)<\/(?:em|i)>/gi, (_, text2) => `*${text2.trim()}*`);
22695
23938
  md = md.replace(/<hr\s*\/?>/gi, "\n---\n");
22696
23939
  md = md.replace(/<table[^>]*>([\s\S]*?)<\/table>/gi, (_, tableContent) => {
22697
23940
  const rows = [];
@@ -22728,7 +23971,7 @@ ${rows.join("\n")}
22728
23971
  }
22729
23972
  var webFetchTool = defineTool({
22730
23973
  name: "web_fetch",
22731
- description: `Fetch a URL and convert its content to clean markdown. Extracts main content, strips navigation/ads, and returns readable text.
23974
+ description: `Fetch the content of a specific URL and return it as clean, readable markdown text. Use this when you already have the exact URL \u2014 for example a documentation page, a GitHub file, or an API response \u2014 and want to read its content. Do NOT use this to find information without a URL; use web_search instead to discover relevant URLs first. By default strips navigation menus, headers, and ads to return only the main content; set extractContent: false to get the raw HTML/text.
22732
23975
 
22733
23976
  Examples:
22734
23977
  - Fetch documentation: { "url": "https://docs.example.com/api" }
@@ -23373,9 +24616,9 @@ async function fileExists(filePath) {
23373
24616
  return false;
23374
24617
  }
23375
24618
  }
23376
- async function fileExists2(path42) {
24619
+ async function fileExists2(path44) {
23377
24620
  try {
23378
- await access(path42);
24621
+ await access(path44);
23379
24622
  return true;
23380
24623
  } catch {
23381
24624
  return false;
@@ -23465,7 +24708,7 @@ async function detectMaturity(cwd) {
23465
24708
  if (!hasLintConfig && hasPackageJson) {
23466
24709
  try {
23467
24710
  const pkgRaw = await import('fs/promises').then(
23468
- (fs39) => fs39.readFile(join(cwd, "package.json"), "utf-8")
24711
+ (fs41) => fs41.readFile(join(cwd, "package.json"), "utf-8")
23469
24712
  );
23470
24713
  const pkg = JSON.parse(pkgRaw);
23471
24714
  if (pkg.scripts?.lint || pkg.scripts?.["lint:fix"]) {
@@ -24309,9 +25552,10 @@ Examples:
24309
25552
  exclude: z.array(z.string()).optional().describe("Additional patterns to exclude"),
24310
25553
  languages: z.array(z.enum(["typescript", "javascript", "python", "java", "go", "rust"])).optional().describe("Languages to parse (auto-detected if not specified)"),
24311
25554
  maxFiles: z.number().min(1).max(1e3).optional().default(DEFAULT_MAX_FILES).describe("Maximum files to process"),
24312
- depth: z.enum(["overview", "detailed"]).optional().default("overview").describe("Level of detail")
25555
+ depth: z.enum(["overview", "detailed"]).optional().default("overview").describe("Level of detail"),
25556
+ includeTests: z.boolean().optional().default(false).describe("Include test/spec files in the map")
24313
25557
  }),
24314
- async execute({ path: rootPath, include, exclude, languages, maxFiles, depth }) {
25558
+ async execute({ path: rootPath, include, exclude, languages, maxFiles, depth, includeTests }) {
24315
25559
  const startTime = performance.now();
24316
25560
  const absPath = path27.resolve(rootPath);
24317
25561
  try {
@@ -24339,7 +25583,12 @@ Examples:
24339
25583
  const allExts = Object.values(LANGUAGE_EXTENSIONS).flat();
24340
25584
  pattern = `**/*{${allExts.join(",")}}`;
24341
25585
  }
24342
- const excludePatterns = [...DEFAULT_EXCLUDES, ...exclude ?? []];
25586
+ const excludePatterns = [
25587
+ ...DEFAULT_EXCLUDES.filter(
25588
+ (pattern2) => includeTests ? !pattern2.includes("*.test.") && !pattern2.includes("*.spec.") : true
25589
+ ),
25590
+ ...exclude ?? []
25591
+ ];
24343
25592
  const files = await glob14(pattern, {
24344
25593
  cwd: absPath,
24345
25594
  ignore: excludePatterns,
@@ -24439,8 +25688,7 @@ async function saveMemory(scope, memory) {
24439
25688
  }
24440
25689
  var createMemoryTool = defineTool({
24441
25690
  name: "create_memory",
24442
- description: `Save a memory (key-value pair) that persists between sessions.
24443
- Use for storing project conventions, patterns, preferences, and learnings.
25691
+ description: `Persist a named key-value fact that survives across sessions \u2014 use this for project conventions, patterns, user preferences, or discovered constraints you'll need later. If the key already exists the value is overwritten. Do NOT use this for temporary scratch data within a single session; do NOT use this to store file contents \u2014 use write_file for that.
24444
25692
 
24445
25693
  Examples:
24446
25694
  - Save convention: { "key": "naming-convention", "value": "Use camelCase for variables", "tags": ["style"] }
@@ -24497,7 +25745,7 @@ Examples:
24497
25745
  });
24498
25746
  var recallMemoryTool = defineTool({
24499
25747
  name: "recall_memory",
24500
- description: `Search and recall stored memories by key, tags, or free text query.
25748
+ description: `Search previously saved memories by key substring, tags, or free-text value match. Use this at the start of a task to check if relevant conventions or patterns were already learned. Returns full memory content. Do NOT use this to list all memories (use list_memories) or to search file content (use grep).
24501
25749
 
24502
25750
  Examples:
24503
25751
  - By key substring: { "query": "naming" }
@@ -24552,7 +25800,7 @@ Examples:
24552
25800
  });
24553
25801
  var listMemoriesTool = defineTool({
24554
25802
  name: "list_memories",
24555
- description: `List all stored memories with optional filtering. Returns lightweight index entries.
25803
+ description: `List stored memory keys and tags without loading full values \u2014 useful for browsing what has been saved before recalling specific entries. Do NOT use this to get memory content (use recall_memory for that).
24556
25804
 
24557
25805
  Examples:
24558
25806
  - List all: { "scope": "all" }
@@ -24838,10 +26086,10 @@ function chunkContent(content, chunkSize) {
24838
26086
  const chunks = [];
24839
26087
  for (let i = 0; i < lines.length; i += chunkSize) {
24840
26088
  const chunkLines = lines.slice(i, Math.min(i + chunkSize, lines.length));
24841
- const text = chunkLines.join("\n").trim();
24842
- if (text.length > 10) {
26089
+ const text2 = chunkLines.join("\n").trim();
26090
+ if (text2.length > 10) {
24843
26091
  chunks.push({
24844
- text,
26092
+ text: text2,
24845
26093
  startLine: i + 1,
24846
26094
  endLine: Math.min(i + chunkSize, lines.length)
24847
26095
  });
@@ -24849,8 +26097,8 @@ function chunkContent(content, chunkSize) {
24849
26097
  }
24850
26098
  return chunks;
24851
26099
  }
24852
- function simpleEmbedding(text) {
24853
- const words = text.toLowerCase().replace(/[^\w\s]/g, " ").split(/\s+/).filter((w) => w.length > 1);
26100
+ function simpleEmbedding(text2) {
26101
+ const words = text2.toLowerCase().replace(/[^\w\s]/g, " ").split(/\s+/).filter((w) => w.length > 1);
24854
26102
  const freq = /* @__PURE__ */ new Map();
24855
26103
  for (const word of words) {
24856
26104
  freq.set(word, (freq.get(word) ?? 0) + 1);
@@ -24876,7 +26124,7 @@ function simpleEmbedding(text) {
24876
26124
  }
24877
26125
  var embedFn = null;
24878
26126
  var usingFallbackEmbedding = false;
24879
- async function getEmbedding(text) {
26127
+ async function getEmbedding(text2) {
24880
26128
  if (!embedFn) {
24881
26129
  try {
24882
26130
  const transformers = await import('@xenova/transformers');
@@ -24893,7 +26141,7 @@ async function getEmbedding(text) {
24893
26141
  usingFallbackEmbedding = true;
24894
26142
  }
24895
26143
  }
24896
- return embedFn(text);
26144
+ return embedFn(text2);
24897
26145
  }
24898
26146
  async function loadIndex2(indexDir) {
24899
26147
  try {
@@ -25440,23 +26688,23 @@ Examples:
25440
26688
  const pdfData = await pdfParse.default(dataBuffer, {
25441
26689
  max: maxPages
25442
26690
  });
25443
- let text = pdfData.text;
26691
+ let text2 = pdfData.text;
25444
26692
  let truncated = false;
25445
26693
  const totalPages = pdfData.numpages;
25446
26694
  if (pages) {
25447
26695
  const range = parsePageRange(pages, totalPages);
25448
- const pageTexts = text.split(/\f/);
26696
+ const pageTexts = text2.split(/\f/);
25449
26697
  if (pageTexts.length > 1) {
25450
26698
  const selectedPages = pageTexts.slice(range.start - 1, range.end);
25451
- text = selectedPages.join("\n\n--- Page Break ---\n\n");
26699
+ text2 = selectedPages.join("\n\n--- Page Break ---\n\n");
25452
26700
  }
25453
26701
  }
25454
- if (text.length > 5e5) {
25455
- text = text.slice(0, 5e5);
26702
+ if (text2.length > 5e5) {
26703
+ text2 = text2.slice(0, 5e5);
25456
26704
  truncated = true;
25457
26705
  }
25458
26706
  return {
25459
- text,
26707
+ text: text2,
25460
26708
  pages: totalPages,
25461
26709
  metadata: {
25462
26710
  title: pdfData.info?.Title,
@@ -25555,14 +26803,14 @@ Examples:
25555
26803
  const mimeType = MIME_TYPES[ext] ?? "image/png";
25556
26804
  const selectedProvider = provider ?? "anthropic";
25557
26805
  let description;
25558
- let model;
26806
+ let model2;
25559
26807
  try {
25560
26808
  if (selectedProvider === "anthropic") {
25561
- model = "claude-sonnet-4-20250514";
26809
+ model2 = "claude-sonnet-4-20250514";
25562
26810
  const { default: Anthropic2 } = await import('@anthropic-ai/sdk');
25563
26811
  const client = new Anthropic2();
25564
26812
  const response = await client.messages.create({
25565
- model,
26813
+ model: model2,
25566
26814
  max_tokens: 4096,
25567
26815
  messages: [
25568
26816
  {
@@ -25586,7 +26834,7 @@ Examples:
25586
26834
  });
25587
26835
  description = response.content.filter((block) => block.type === "text").map((block) => block.text).join("\n") || "No description generated";
25588
26836
  } else if (selectedProvider === "openai") {
25589
- model = "gpt-4o";
26837
+ model2 = "gpt-4o";
25590
26838
  const { default: OpenAI3 } = await import('openai');
25591
26839
  const client = new OpenAI3();
25592
26840
  const openaiMessages = [
@@ -25607,13 +26855,13 @@ Examples:
25607
26855
  }
25608
26856
  ];
25609
26857
  const response = await client.chat.completions.create({
25610
- model,
26858
+ model: model2,
25611
26859
  max_tokens: 4096,
25612
26860
  messages: openaiMessages
25613
26861
  });
25614
26862
  description = response.choices[0]?.message?.content ?? "No description generated";
25615
26863
  } else if (selectedProvider === "gemini") {
25616
- model = "gemini-2.0-flash";
26864
+ model2 = "gemini-2.0-flash";
25617
26865
  const { GoogleGenAI: GoogleGenAI2 } = await import('@google/genai');
25618
26866
  const apiKey = process.env.GOOGLE_API_KEY ?? process.env.GEMINI_API_KEY;
25619
26867
  if (!apiKey) {
@@ -25624,7 +26872,7 @@ Examples:
25624
26872
  }
25625
26873
  const genAI = new GoogleGenAI2({ apiKey });
25626
26874
  const result = await genAI.models.generateContent({
25627
- model,
26875
+ model: model2,
25628
26876
  contents: [
25629
26877
  {
25630
26878
  role: "user",
@@ -25667,7 +26915,7 @@ Examples:
25667
26915
  return {
25668
26916
  description,
25669
26917
  provider: selectedProvider,
25670
- model,
26918
+ model: model2,
25671
26919
  duration: performance.now() - startTime,
25672
26920
  imageSize: imageBuffer.length,
25673
26921
  format: ext.slice(1)
@@ -25947,8 +27195,8 @@ async function analyzeFile(filePath, includeAst = false) {
25947
27195
  };
25948
27196
  }
25949
27197
  async function analyzeDirectory(dirPath) {
25950
- const { glob: glob17 } = await import('glob');
25951
- const files = await glob17("**/*.{ts,tsx,js,jsx}", {
27198
+ const { glob: glob18 } = await import('glob');
27199
+ const files = await glob18("**/*.{ts,tsx,js,jsx}", {
25952
27200
  cwd: dirPath,
25953
27201
  ignore: ["**/node_modules/**", "**/dist/**", "**/build/**"],
25954
27202
  absolute: true
@@ -26020,6 +27268,329 @@ var analyzeDirectoryTool = defineTool({
26020
27268
  }
26021
27269
  });
26022
27270
  var codeAnalyzerTools = [analyzeFileTool, analyzeDirectoryTool];
27271
+ var SOURCE_GLOBS = ["**/*.ts", "**/*.tsx", "**/*.js", "**/*.jsx", "**/*.mjs", "**/*.cjs"];
27272
+ var DEFAULT_EXCLUDES3 = [
27273
+ "**/node_modules/**",
27274
+ "**/.git/**",
27275
+ "**/dist/**",
27276
+ "**/build/**",
27277
+ "**/coverage/**",
27278
+ "**/*.d.ts"
27279
+ ];
27280
+ async function commandAvailable(command) {
27281
+ try {
27282
+ await execa(command, ["--version"], { timeout: 3e3 });
27283
+ return true;
27284
+ } catch {
27285
+ return false;
27286
+ }
27287
+ }
27288
+ async function getSourceFiles(root, maxFiles) {
27289
+ const files = await glob(SOURCE_GLOBS, {
27290
+ cwd: root,
27291
+ absolute: false,
27292
+ ignore: DEFAULT_EXCLUDES3,
27293
+ nodir: true
27294
+ });
27295
+ return files.slice(0, maxFiles);
27296
+ }
27297
+ async function getFileSymbols(filePath) {
27298
+ const absolutePath = path17__default.resolve(filePath);
27299
+ const content = await fs16__default.readFile(absolutePath, "utf-8");
27300
+ const language = detectLanguage3(absolutePath);
27301
+ if (language !== "typescript" && language !== "javascript") {
27302
+ return [];
27303
+ }
27304
+ return parseTypeScript(content).definitions.map((definition) => ({
27305
+ file: filePath,
27306
+ name: definition.name,
27307
+ type: definition.type,
27308
+ line: definition.line,
27309
+ exported: definition.exported,
27310
+ signature: definition.signature
27311
+ }));
27312
+ }
27313
+ var lspStatusTool = defineTool({
27314
+ name: "lsp_status",
27315
+ description: "Check optional language-server availability. Use before LSP-style navigation when you need to know whether Coco is using static fallbacks.",
27316
+ category: "search",
27317
+ parameters: z.object({}),
27318
+ async execute() {
27319
+ return {
27320
+ languageServers: [
27321
+ {
27322
+ name: "typescript-language-server",
27323
+ available: await commandAvailable("typescript-language-server")
27324
+ },
27325
+ { name: "tsserver", available: await commandAvailable("tsserver") }
27326
+ ],
27327
+ fallbackMode: "static-analysis"
27328
+ };
27329
+ }
27330
+ });
27331
+ var lspDocumentSymbolsTool = defineTool({
27332
+ name: "lsp_document_symbols",
27333
+ description: "Return LSP-style document symbols for a TypeScript/JavaScript file using static analysis fallback.",
27334
+ category: "search",
27335
+ parameters: z.object({
27336
+ file: z.string().describe("File path to inspect")
27337
+ }),
27338
+ async execute({ file }) {
27339
+ return { symbols: await getFileSymbols(file) };
27340
+ }
27341
+ });
27342
+ var lspWorkspaceSymbolsTool = defineTool({
27343
+ name: "lsp_workspace_symbols",
27344
+ description: "Find LSP-style workspace symbols by name across TypeScript/JavaScript files using static analysis fallback.",
27345
+ category: "search",
27346
+ parameters: z.object({
27347
+ query: z.string().describe("Symbol name or substring to find"),
27348
+ path: z.string().optional().describe("Workspace directory, defaults to cwd"),
27349
+ maxFiles: z.number().optional().default(300),
27350
+ maxResults: z.number().optional().default(100)
27351
+ }),
27352
+ async execute({ query, path: workspacePath, maxFiles = 300, maxResults = 100 }) {
27353
+ const root = path17__default.resolve(workspacePath ?? process.cwd());
27354
+ const files = await getSourceFiles(root, maxFiles);
27355
+ const lowerQuery = query.toLowerCase();
27356
+ const symbols = [];
27357
+ for (const file of files) {
27358
+ const fileSymbols = await getFileSymbols(path17__default.join(root, file));
27359
+ for (const symbol of fileSymbols) {
27360
+ if (!symbol.name.toLowerCase().includes(lowerQuery)) continue;
27361
+ symbols.push({ ...symbol, file });
27362
+ if (symbols.length >= maxResults) {
27363
+ return { symbols, searchedFiles: files.length, truncated: true };
27364
+ }
27365
+ }
27366
+ }
27367
+ return { symbols, searchedFiles: files.length, truncated: false };
27368
+ }
27369
+ });
27370
+ var lspDefinitionTool = defineTool({
27371
+ name: "lsp_definition",
27372
+ description: "Find the likely definition of a symbol using exported symbols first, then local definitions.",
27373
+ category: "search",
27374
+ parameters: z.object({
27375
+ symbol: z.string().describe("Exact symbol name to locate"),
27376
+ path: z.string().optional().describe("Workspace directory, defaults to cwd"),
27377
+ maxFiles: z.number().optional().default(300)
27378
+ }),
27379
+ async execute({ symbol, path: workspacePath, maxFiles = 300 }) {
27380
+ const root = path17__default.resolve(workspacePath ?? process.cwd());
27381
+ const files = await getSourceFiles(root, maxFiles);
27382
+ const candidates = [];
27383
+ for (const file of files) {
27384
+ const fileSymbols = await getFileSymbols(path17__default.join(root, file));
27385
+ for (const candidate of fileSymbols) {
27386
+ if (candidate.name !== symbol) continue;
27387
+ candidates.push({ ...candidate, file });
27388
+ }
27389
+ }
27390
+ const definition = candidates.find((candidate) => candidate.exported) ?? candidates[0];
27391
+ return { definition, candidates };
27392
+ }
27393
+ });
27394
+ var lspReferencesTool = defineTool({
27395
+ name: "lsp_references",
27396
+ description: "Find likely references to a symbol across TypeScript/JavaScript files using whole-word text search.",
27397
+ category: "search",
27398
+ parameters: z.object({
27399
+ symbol: z.string().describe("Symbol name to find"),
27400
+ path: z.string().optional().describe("Workspace directory, defaults to cwd"),
27401
+ maxFiles: z.number().optional().default(300),
27402
+ maxResults: z.number().optional().default(100)
27403
+ }),
27404
+ async execute({ symbol, path: workspacePath, maxFiles = 300, maxResults = 100 }) {
27405
+ const root = path17__default.resolve(workspacePath ?? process.cwd());
27406
+ const files = await getSourceFiles(root, maxFiles);
27407
+ const pattern = new RegExp(`\\b${escapeRegExp(symbol)}\\b`);
27408
+ const references = [];
27409
+ for (const file of files) {
27410
+ const absolutePath = path17__default.join(root, file);
27411
+ const content = await fs16__default.readFile(absolutePath, "utf-8");
27412
+ const lines = content.split("\n");
27413
+ for (let index = 0; index < lines.length; index++) {
27414
+ const line = lines[index] ?? "";
27415
+ const match = pattern.exec(line);
27416
+ if (!match) continue;
27417
+ references.push({
27418
+ file,
27419
+ line: index + 1,
27420
+ column: match.index + 1,
27421
+ content: line.trim()
27422
+ });
27423
+ if (references.length >= maxResults) {
27424
+ return { references, searchedFiles: files.length, truncated: true };
27425
+ }
27426
+ }
27427
+ }
27428
+ return { references, searchedFiles: files.length, truncated: false };
27429
+ }
27430
+ });
27431
+ function escapeRegExp(value) {
27432
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
27433
+ }
27434
+ var lspTools = [
27435
+ lspStatusTool,
27436
+ lspDocumentSymbolsTool,
27437
+ lspWorkspaceSymbolsTool,
27438
+ lspDefinitionTool,
27439
+ lspReferencesTool
27440
+ ];
27441
+ var fs34 = await import('fs/promises');
27442
+ var path36 = await import('path');
27443
+ function cachePath(root) {
27444
+ return path36.join(root, ".coco", "cache", "repo-index.json");
27445
+ }
27446
+ function normalizeText(value) {
27447
+ return value.toLowerCase().replace(/[^a-z0-9_./:-]+/g, " ");
27448
+ }
27449
+ function queryTerms(query) {
27450
+ return [
27451
+ ...new Set(
27452
+ normalizeText(query).split(/\s+/).filter((term) => term.length >= 2)
27453
+ )
27454
+ ];
27455
+ }
27456
+ function importTargetToPath(importTarget) {
27457
+ return importTarget.replace(/^\.\//, "").replace(/\.(js|ts|tsx|jsx|mjs|cjs)$/, "");
27458
+ }
27459
+ function buildGraph(root, map) {
27460
+ const inbound = /* @__PURE__ */ new Map();
27461
+ const files = new Set(map.files.map((file) => file.path.replace(/\.[^.]+$/, "")));
27462
+ for (const file of map.files) {
27463
+ for (const importTarget of file.imports) {
27464
+ const normalized = importTargetToPath(importTarget);
27465
+ for (const candidate of files) {
27466
+ if (candidate.endsWith(normalized) || normalized.endsWith(candidate)) {
27467
+ inbound.set(candidate, (inbound.get(candidate) ?? 0) + 1);
27468
+ }
27469
+ }
27470
+ }
27471
+ }
27472
+ return {
27473
+ root,
27474
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
27475
+ files: map.files.map((file) => {
27476
+ const withoutExt = file.path.replace(/\.[^.]+$/, "");
27477
+ return {
27478
+ ...file,
27479
+ inboundImports: inbound.get(withoutExt) ?? 0,
27480
+ testRelated: /(?:^|[/.-])(test|spec|__tests__)(?:[/.-]|$)/i.test(file.path)
27481
+ };
27482
+ }),
27483
+ summary: map.summary
27484
+ };
27485
+ }
27486
+ async function readCachedGraph(root) {
27487
+ try {
27488
+ const raw = await fs34.readFile(cachePath(root), "utf-8");
27489
+ return JSON.parse(raw);
27490
+ } catch {
27491
+ return null;
27492
+ }
27493
+ }
27494
+ async function writeCachedGraph(root, graph) {
27495
+ const file = cachePath(root);
27496
+ await fs34.mkdir(path36.dirname(file), { recursive: true });
27497
+ await fs34.writeFile(file, JSON.stringify(graph, null, 2) + "\n", "utf-8");
27498
+ }
27499
+ async function loadGraph(root, refresh) {
27500
+ if (!refresh) {
27501
+ const cached = await readCachedGraph(root);
27502
+ if (cached) return cached;
27503
+ }
27504
+ const map = await codebaseMapTool.execute({
27505
+ path: root,
27506
+ maxFiles: 500,
27507
+ depth: "detailed",
27508
+ includeTests: true
27509
+ });
27510
+ const graph = buildGraph(root, map);
27511
+ await writeCachedGraph(root, graph);
27512
+ return graph;
27513
+ }
27514
+ function scoreFile(file, terms, mode, changedFiles) {
27515
+ let score = 0;
27516
+ const reasons = [];
27517
+ const pathText = normalizeText(file.path);
27518
+ const symbolText = normalizeText(file.definitions.map((def) => def.name).join(" "));
27519
+ const importText = normalizeText([...file.imports, ...file.exports].join(" "));
27520
+ for (const term of terms) {
27521
+ if (pathText.includes(term)) {
27522
+ score += 8;
27523
+ reasons.push(`path:${term}`);
27524
+ }
27525
+ if (symbolText.includes(term)) {
27526
+ score += 6;
27527
+ reasons.push(`symbol:${term}`);
27528
+ }
27529
+ if (importText.includes(term)) {
27530
+ score += 3;
27531
+ reasons.push(`import/export:${term}`);
27532
+ }
27533
+ }
27534
+ if (changedFiles.has(file.path)) {
27535
+ score += 10;
27536
+ reasons.push("changed-file");
27537
+ }
27538
+ if (file.inboundImports > 0) {
27539
+ score += Math.min(6, file.inboundImports);
27540
+ reasons.push(`centrality:${file.inboundImports}`);
27541
+ }
27542
+ if ((mode === "debug" || mode === "review") && file.testRelated) {
27543
+ score += 4;
27544
+ reasons.push("test-related");
27545
+ }
27546
+ if (file.exports.length > 0) {
27547
+ score += 1;
27548
+ }
27549
+ return {
27550
+ path: file.path,
27551
+ score,
27552
+ reasons: [...new Set(reasons)],
27553
+ language: file.language,
27554
+ lineCount: file.lineCount,
27555
+ definitions: file.definitions.slice(0, 20),
27556
+ imports: file.imports.slice(0, 20),
27557
+ exports: file.exports.slice(0, 20)
27558
+ };
27559
+ }
27560
+ async function getRepoContext(request) {
27561
+ const root = path36.resolve(request.path ?? ".");
27562
+ const budget = request.budget ?? 12;
27563
+ const graph = await loadGraph(root, request.refresh ?? false);
27564
+ const terms = queryTerms(request.query);
27565
+ const changedFiles = new Set(request.changedFiles ?? []);
27566
+ const items = graph.files.map((file) => scoreFile(file, terms, request.mode, changedFiles)).filter((item) => item.score > 0).sort((a, b) => b.score - a.score || a.path.localeCompare(b.path)).slice(0, budget);
27567
+ return {
27568
+ graph: {
27569
+ root: graph.root,
27570
+ generatedAt: graph.generatedAt,
27571
+ totalFiles: graph.summary.totalFiles,
27572
+ totalDefinitions: graph.summary.totalDefinitions
27573
+ },
27574
+ query: request.query,
27575
+ budget,
27576
+ items
27577
+ };
27578
+ }
27579
+ var repoContextTool = defineTool({
27580
+ name: "repo_context",
27581
+ description: "Return ranked, token-efficient repository context for a task using symbols, imports, tests, and centrality.",
27582
+ category: "search",
27583
+ parameters: z.object({
27584
+ path: z.string().optional().default(".").describe("Repository root"),
27585
+ query: z.string().min(1).describe("Task or search query to rank files against"),
27586
+ budget: z.number().min(1).max(50).optional().default(12).describe("Maximum files to return"),
27587
+ mode: z.enum(["ask", "plan", "build", "debug", "review", "architect"]).optional().describe("Agent mode to bias ranking"),
27588
+ changedFiles: z.array(z.string()).optional().describe("Files already changed or selected"),
27589
+ refresh: z.boolean().optional().default(false).describe("Refresh persistent repo index cache")
27590
+ }),
27591
+ execute: getRepoContext
27592
+ });
27593
+ var repoIntelligenceTools = [repoContextTool];
26023
27594
  var AgentTaskQueue = class {
26024
27595
  tasks = /* @__PURE__ */ new Map();
26025
27596
  completionOrder = [];
@@ -26328,15 +27899,15 @@ ${completed.map((r) => `- ${r.agentId}: Success`).join("\n")}`;
26328
27899
  }
26329
27900
  });
26330
27901
  var agentCoordinatorTools = [createAgentPlanTool, delegateTaskTool, aggregateResultsTool];
26331
- var fs33 = await import('fs/promises');
27902
+ var fs35 = await import('fs/promises');
26332
27903
  var SuggestImprovementsSchema = z.object({
26333
27904
  filePath: z.string().describe("File to analyze for improvement suggestions"),
26334
27905
  context: z.string().optional().describe("Additional context about the code")
26335
27906
  });
26336
27907
  async function analyzeAndSuggest(filePath, _context) {
26337
- let rawContent = await fs33.readFile(filePath, "utf-8");
27908
+ let rawContent = await fs35.readFile(filePath, "utf-8");
26338
27909
  if (typeof rawContent !== "string") {
26339
- const defaultReadFile = fs33.default?.readFile;
27910
+ const defaultReadFile = fs35.default?.readFile;
26340
27911
  if (typeof defaultReadFile === "function") {
26341
27912
  rawContent = await defaultReadFile(filePath, "utf-8");
26342
27913
  }
@@ -26433,7 +28004,7 @@ async function analyzeAndSuggest(filePath, _context) {
26433
28004
  if (filePath.endsWith(".ts") && !filePath.includes("test") && !filePath.includes(".d.ts") && line.includes("export ")) {
26434
28005
  const testPath = filePath.replace(".ts", ".test.ts");
26435
28006
  try {
26436
- await fs33.access(testPath);
28007
+ await fs35.access(testPath);
26437
28008
  } catch {
26438
28009
  suggestions.push({
26439
28010
  type: "testing",
@@ -26490,7 +28061,7 @@ var calculateCodeScoreTool = defineTool({
26490
28061
  async execute(input) {
26491
28062
  const { filePath } = input;
26492
28063
  const suggestions = await analyzeAndSuggest(filePath);
26493
- const content = await fs33.readFile(filePath, "utf-8");
28064
+ const content = await fs35.readFile(filePath, "utf-8");
26494
28065
  const lines = content.split("\n");
26495
28066
  const nonEmptyLines = lines.filter((l) => l.trim()).length;
26496
28067
  let score = 100;
@@ -26524,8 +28095,8 @@ var calculateCodeScoreTool = defineTool({
26524
28095
  }
26525
28096
  });
26526
28097
  var smartSuggestionsTools = [suggestImprovementsTool, calculateCodeScoreTool];
26527
- var fs34 = await import('fs/promises');
26528
- var path35 = await import('path');
28098
+ var fs36 = await import('fs/promises');
28099
+ var path37 = await import('path');
26529
28100
  var ContextMemoryStore = class {
26530
28101
  items = /* @__PURE__ */ new Map();
26531
28102
  learnings = /* @__PURE__ */ new Map();
@@ -26537,7 +28108,7 @@ var ContextMemoryStore = class {
26537
28108
  }
26538
28109
  async load() {
26539
28110
  try {
26540
- const content = await fs34.readFile(this.storePath, "utf-8");
28111
+ const content = await fs36.readFile(this.storePath, "utf-8");
26541
28112
  const data = JSON.parse(content);
26542
28113
  this.items = new Map(Object.entries(data.items || {}));
26543
28114
  this.learnings = new Map(Object.entries(data.learnings || {}));
@@ -26545,15 +28116,15 @@ var ContextMemoryStore = class {
26545
28116
  }
26546
28117
  }
26547
28118
  async save() {
26548
- const dir = path35.dirname(this.storePath);
26549
- await fs34.mkdir(dir, { recursive: true });
28119
+ const dir = path37.dirname(this.storePath);
28120
+ await fs36.mkdir(dir, { recursive: true });
26550
28121
  const data = {
26551
28122
  sessionId: this.sessionId,
26552
28123
  items: Object.fromEntries(this.items),
26553
28124
  learnings: Object.fromEntries(this.learnings),
26554
28125
  savedAt: Date.now()
26555
28126
  };
26556
- await fs34.writeFile(this.storePath, JSON.stringify(data, null, 2));
28127
+ await fs36.writeFile(this.storePath, JSON.stringify(data, null, 2));
26557
28128
  }
26558
28129
  addContext(id, item) {
26559
28130
  this.items.set(id, item);
@@ -26718,11 +28289,11 @@ var contextEnhancerTools = [
26718
28289
  recordLearningTool,
26719
28290
  getLearnedPatternsTool
26720
28291
  ];
26721
- var fs35 = await import('fs/promises');
26722
- var path36 = await import('path');
28292
+ var fs37 = await import('fs/promises');
28293
+ var path38 = await import('path');
26723
28294
  async function discoverSkills(skillsDir) {
26724
28295
  try {
26725
- const files = await fs35.readdir(skillsDir);
28296
+ const files = await fs37.readdir(skillsDir);
26726
28297
  return files.filter((f) => f.endsWith(".ts") || f.endsWith(".js"));
26727
28298
  } catch {
26728
28299
  return [];
@@ -26730,12 +28301,12 @@ async function discoverSkills(skillsDir) {
26730
28301
  }
26731
28302
  async function loadSkillMetadata(skillPath) {
26732
28303
  try {
26733
- const content = await fs35.readFile(skillPath, "utf-8");
28304
+ const content = await fs37.readFile(skillPath, "utf-8");
26734
28305
  const nameMatch = content.match(/@name\s+(\S+)/);
26735
28306
  const descMatch = content.match(/@description\s+(.+)/);
26736
28307
  const versionMatch = content.match(/@version\s+(\S+)/);
26737
28308
  return {
26738
- name: nameMatch?.[1] || path36.basename(skillPath, path36.extname(skillPath)),
28309
+ name: nameMatch?.[1] || path38.basename(skillPath, path38.extname(skillPath)),
26739
28310
  description: descMatch?.[1] || "No description",
26740
28311
  version: versionMatch?.[1] || "1.0.0",
26741
28312
  dependencies: []
@@ -26779,7 +28350,7 @@ var discoverSkillsTool = defineTool({
26779
28350
  const { skillsDir } = input;
26780
28351
  const skills = await discoverSkills(skillsDir);
26781
28352
  const metadata = await Promise.all(
26782
- skills.map((s) => loadSkillMetadata(path36.join(skillsDir, s)))
28353
+ skills.map((s) => loadSkillMetadata(path38.join(skillsDir, s)))
26783
28354
  );
26784
28355
  return {
26785
28356
  skillsDir,
@@ -27074,7 +28645,7 @@ async function ghExec(args, cwd) {
27074
28645
  }
27075
28646
  var ghCheckAuthTool = defineTool({
27076
28647
  name: "gh_check_auth",
27077
- description: "Check if the GitHub CLI is installed and authenticated.",
28648
+ description: "Verify the gh CLI is installed and the user is logged into GitHub. Call this before any other gh_ tool to confirm authentication is working. Returns the logged-in username if authenticated.",
27078
28649
  category: "git",
27079
28650
  parameters: z.object({
27080
28651
  cwd: z.string().optional()
@@ -27094,7 +28665,7 @@ var ghCheckAuthTool = defineTool({
27094
28665
  });
27095
28666
  var ghRepoInfoTool = defineTool({
27096
28667
  name: "gh_repo_info",
27097
- description: "Get GitHub repository information (name, default branch, URL).",
28668
+ description: "Get the remote GitHub repository's name, owner, default branch, and URL from within the current git working directory. Use before creating PRs to confirm the target repo. Requires gh_check_auth to pass first.",
27098
28669
  category: "git",
27099
28670
  parameters: z.object({
27100
28671
  cwd: z.string().optional()
@@ -27116,7 +28687,7 @@ var ghRepoInfoTool = defineTool({
27116
28687
  });
27117
28688
  var ghPrCreateTool = defineTool({
27118
28689
  name: "gh_pr_create",
27119
- description: "Create a GitHub pull request.",
28690
+ description: "Open a pull request on GitHub from the current branch. Requires commits to be pushed first (use git_push with setUpstream: true). Do NOT use this if a PR for this branch already exists \u2014 use gh_pr_list to check first. Use draft: true for work in progress.",
27120
28691
  category: "git",
27121
28692
  parameters: z.object({
27122
28693
  title: z.string().describe("PR title"),
@@ -27140,7 +28711,7 @@ var ghPrCreateTool = defineTool({
27140
28711
  });
27141
28712
  var ghPrMergeTool = defineTool({
27142
28713
  name: "gh_pr_merge",
27143
- description: "Merge a GitHub pull request.",
28714
+ description: "Merge a pull request into its base branch. Use squash (default) for feature branches to keep history clean. Always confirm with gh_pr_checks first to ensure CI passed. Do NOT merge if anyFailed is true.",
27144
28715
  category: "git",
27145
28716
  parameters: z.object({
27146
28717
  number: z.number().describe("PR number"),
@@ -27161,7 +28732,7 @@ var ghPrMergeTool = defineTool({
27161
28732
  });
27162
28733
  var ghPrChecksTool = defineTool({
27163
28734
  name: "gh_pr_checks",
27164
- description: "Get CI check statuses for a pull request.",
28735
+ description: "Poll the CI check results for a pull request \u2014 returns pass/fail/pending per check and convenience flags (allPassed, anyFailed). Call this after pushing to confirm CI is green before merging. Check anyPending to know if results are still arriving.",
27165
28736
  category: "git",
27166
28737
  parameters: z.object({
27167
28738
  number: z.number().describe("PR number"),
@@ -27195,7 +28766,7 @@ var ghPrChecksTool = defineTool({
27195
28766
  });
27196
28767
  var ghPrListTool = defineTool({
27197
28768
  name: "gh_pr_list",
27198
- description: "List pull requests, optionally filtered by head branch.",
28769
+ description: "List open (or all) pull requests for this repository, optionally filtered to a specific branch. Use before gh_pr_create to ensure a PR for the current branch doesn't already exist. Returns PR number, title, URL, and state.",
27199
28770
  category: "git",
27200
28771
  parameters: z.object({
27201
28772
  head: z.string().optional().describe("Filter by head branch name"),
@@ -27212,7 +28783,7 @@ var ghPrListTool = defineTool({
27212
28783
  });
27213
28784
  var ghReleaseCreateTool = defineTool({
27214
28785
  name: "gh_release_create",
27215
- description: "Create a GitHub release with notes.",
28786
+ description: "Publish a versioned GitHub release attached to a tag. The tag must already exist in the repo (push it with git_push first). Provide markdown release notes. Use prerelease: true for release candidates or beta builds.",
27216
28787
  category: "git",
27217
28788
  parameters: z.object({
27218
28789
  tag: z.string().describe("Tag name (e.g., v1.2.3)"),
@@ -27519,8 +29090,8 @@ var MCPRegistryImpl = class {
27519
29090
  /**
27520
29091
  * Ensure directory exists
27521
29092
  */
27522
- async ensureDir(path42) {
27523
- await mkdir(dirname(path42), { recursive: true });
29093
+ async ensureDir(path44) {
29094
+ await mkdir(dirname(path44), { recursive: true });
27524
29095
  }
27525
29096
  };
27526
29097
 
@@ -27536,6 +29107,8 @@ var MCPClientImpl = class {
27536
29107
  this.requestTimeout = requestTimeout;
27537
29108
  this.setupTransportHandlers();
27538
29109
  }
29110
+ transport;
29111
+ requestTimeout;
27539
29112
  requestId = 0;
27540
29113
  pendingRequests = /* @__PURE__ */ new Map();
27541
29114
  initialized = false;
@@ -27707,6 +29280,7 @@ var StdioTransport = class {
27707
29280
  constructor(config) {
27708
29281
  this.config = config;
27709
29282
  }
29283
+ config;
27710
29284
  process = null;
27711
29285
  messageCallback = null;
27712
29286
  errorCallback = null;
@@ -28246,6 +29820,7 @@ var HTTPTransport = class {
28246
29820
  this.config.timeout = config.timeout ?? 6e4;
28247
29821
  this.config.retries = config.retries ?? 3;
28248
29822
  }
29823
+ config;
28249
29824
  messageCallback = null;
28250
29825
  errorCallback = null;
28251
29826
  // Used to report transport errors to the client
@@ -29314,6 +30889,8 @@ function registerAllTools(registry) {
29314
30889
  ...databaseTools,
29315
30890
  ...astValidatorTools,
29316
30891
  ...codeAnalyzerTools,
30892
+ ...lspTools,
30893
+ ...repoIntelligenceTools,
29317
30894
  ...agentCoordinatorTools,
29318
30895
  ...smartSuggestionsTools,
29319
30896
  ...contextEnhancerTools,