jinzd-ai-cli 0.4.228 → 0.4.230

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/dist/{batch-K6IRL6TU.js → batch-T74D2CCK.js} +3 -3
  2. package/dist/{chunk-DEHVRQWW.js → chunk-4KM53GLG.js} +1 -1
  3. package/dist/{chunk-EEQHP4GK.js → chunk-62R7CACG.js} +101 -302
  4. package/dist/{chunk-JZNKM3RV.js → chunk-6GSDDDEO.js} +1 -1
  5. package/dist/{chunk-LDWTVCE5.js → chunk-7I4GGVIS.js} +1 -1
  6. package/dist/{chunk-JGQ3TULW.js → chunk-DKPHVQUA.js} +1 -1
  7. package/dist/{chunk-MQVC7FJH.js → chunk-F2DUNYGY.js} +21 -36
  8. package/dist/{chunk-ACO2RJY3.js → chunk-ITEGK3IN.js} +1 -1
  9. package/dist/{chunk-32LTIQQN.js → chunk-LMKCS5XH.js} +4 -4
  10. package/dist/{chunk-NI34BUBR.js → chunk-S6SFZP3G.js} +1 -1
  11. package/dist/{chunk-4GF47FW3.js → chunk-SARJYCDV.js} +4 -4
  12. package/dist/{chunk-VSEXYCEE.js → chunk-SKUNYJDW.js} +2 -2
  13. package/dist/{chunk-JO2CAKHA.js → chunk-T3A74XGG.js} +1 -1
  14. package/dist/{chunk-QYQCCIBT.js → chunk-ZWU7FWHO.js} +22 -3
  15. package/dist/{ci-D35MUGEH.js → ci-ADQTAYOZ.js} +5 -5
  16. package/dist/{ci-format-EQ4HGHXR.js → ci-format-KZSTHIEW.js} +2 -2
  17. package/dist/{constants-F2LRIWV2.js → constants-JTHN5JSQ.js} +1 -1
  18. package/dist/{doctor-cli-R3AH5CLF.js → doctor-cli-XTIL3RTQ.js} +5 -5
  19. package/dist/electron-server.js +169 -373
  20. package/dist/{hub-AAYGBUDA.js → hub-BHHNMBCY.js} +2 -2
  21. package/dist/index.js +36 -49
  22. package/dist/{persist-XUXIPYUU.js → persist-I3JI27OK.js} +2 -2
  23. package/dist/{pr-HX6V63FO.js → pr-NUHU64NS.js} +5 -5
  24. package/dist/{run-tests-5QHWA4MF.js → run-tests-HZMY436A.js} +2 -2
  25. package/dist/{run-tests-7SGHDDHL.js → run-tests-M45ZJPR6.js} +1 -1
  26. package/dist/{server-E5XTQG7W.js → server-Q7MNZB4X.js} +4 -4
  27. package/dist/{server-O2YK3VWK.js → server-RCAFE2LO.js} +37 -44
  28. package/dist/{task-orchestrator-T2LUS5ZQ.js → task-orchestrator-IVSLED6U.js} +4 -4
  29. package/dist/{usage-AIHU5PIY.js → usage-KNMT35C2.js} +2 -2
  30. package/dist/web/client/app.js +13 -5
  31. package/dist/web/client/index.html +14 -6
  32. package/package.json +1 -1
@@ -38,7 +38,7 @@ import {
38
38
  VERSION,
39
39
  buildUserIdentityPrompt,
40
40
  runTestsTool
41
- } from "./chunk-LDWTVCE5.js";
41
+ } from "./chunk-7I4GGVIS.js";
42
42
  import {
43
43
  hasSemanticIndex,
44
44
  semanticSearch
@@ -3275,84 +3275,44 @@ var DeepSeekProvider = class extends OpenAICompatibleProvider {
3275
3275
  }
3276
3276
  };
3277
3277
 
3278
- // src/providers/zhipu.ts
3279
- var ZhipuProvider = class extends OpenAICompatibleProvider {
3280
- defaultBaseUrl = "https://open.bigmodel.cn/api/paas/v4";
3281
- // GLM-5 / GLM-5.1 等深度思考模型生成长内容需要较长时间,默认 5 分钟
3282
- defaultTimeout = 3e5;
3283
- info = {
3284
- id: "zhipu",
3285
- displayName: "Zhipu (GLM)",
3286
- // 默认选 GLM-4.6:中文写作口碑最稳 + 200K 上下文 + 价格只有 5.1 的 ~1/2。
3287
- // 需要 Agent 长跑 / 代码工程时再手动 /model glm-5.1。
3288
- defaultModel: "glm-4.6",
3289
- apiKeyEnvVar: "AICLI_API_KEY_ZHIPU",
3290
- requiresApiKey: true,
3291
- baseUrl: this.defaultBaseUrl,
3292
- models: [
3293
- // ── GLM-5.2 系列(2026-06 最新旗舰,主打代码工程) ──
3294
- // 744B MoE / 40B active,与 5.1 同底座,后训练强化超长上下文代码任务。
3295
- // 思考模式 High/Max 由请求参数控制,不另列 model id。
3296
- // 上下文:标准 `glm-5.2` 在 paas/v4 上原生即 1M(open.bigmodel.cn/pricing 定价页
3297
- // 实测口径 1M,¥8/¥28)。曾被移除的 `glm-5.2[1m]` 是 *带后缀的 model code*——那个
3298
- // code 只在 GLM Coding Plan 的 Anthropic 兼容端点存在,paas/v4 不认会报「模型不存在」;
3299
- // 1M 能力本身在标准 code 上就有,无需后缀。
3300
- {
3301
- id: "glm-5.2",
3302
- displayName: "GLM-5.2 (2026-06 Flagship, 1M, Coding)",
3303
- contextWindow: 1048576,
3304
- supportsStreaming: true,
3305
- supportsThinking: true
3306
- },
3307
- // 视觉编程旗舰:原生多模态(图片 / 短视频 / 文本同上下文)。API model code = `glm-5v-turbo`
3308
- // (Z.ai 官方文档代码示例确认)。REPL 用 `@./pic.png` 引用本地图即可走 vision 请求;
3309
- // getVisionModelHint 已识别 `5v` 不拦截。
3310
- {
3311
- id: "glm-5v-turbo",
3312
- displayName: "GLM-5V-Turbo (Multimodal Vision + Coding)",
3313
- contextWindow: 202752,
3314
- supportsStreaming: true
3315
- },
3316
- // ── GLM-5.1 系列(2026-04 旗舰,主打长程 Agent + 代码工程) ──
3317
- {
3318
- id: "glm-5.1",
3319
- displayName: "GLM-5.1 (2026 Flagship, 200K, Agent+Code)",
3320
- contextWindow: 204800,
3321
- supportsStreaming: true,
3322
- supportsThinking: true
3323
- },
3324
- {
3325
- id: "glm-5.1-reasoning",
3326
- displayName: "GLM-5.1 Reasoning (Deep Thinking)",
3327
- contextWindow: 204800,
3328
- supportsStreaming: true,
3329
- supportsThinking: true
3330
- },
3331
- {
3332
- id: "glm-5.1-air",
3333
- displayName: "GLM-5.1 Air (Lightweight 5.1)",
3334
- contextWindow: 204800,
3335
- supportsStreaming: true,
3336
- supportsThinking: true
3337
- },
3338
- // ── GLM-5 系列(2026-02) ──
3339
- {
3340
- id: "glm-5",
3341
- displayName: "GLM-5 (Flagship, Deep Thinking)",
3342
- contextWindow: 131072,
3343
- supportsStreaming: true,
3344
- supportsThinking: true
3345
- },
3346
- // ── GLM-4.6 系列(2025-09,中文写作口碑最佳) ──
3347
- {
3348
- id: "glm-4.6",
3349
- displayName: "GLM-4.6 (200K, \u4E2D\u6587\u5199\u4F5C\u63A8\u8350)",
3350
- contextWindow: 204800,
3351
- supportsStreaming: true
3352
- }
3353
- ]
3278
+ // src/providers/static-config.ts
3279
+ function createStaticProviderClass(config) {
3280
+ return class extends OpenAICompatibleProvider {
3281
+ defaultBaseUrl = config.baseUrl;
3282
+ defaultTimeout = config.defaultTimeout ?? 12e4;
3283
+ enableStreamingToolCalls = config.enableStreamingToolCalls ?? true;
3284
+ reliableContentOnlyTee = config.reliableContentOnlyTee ?? true;
3285
+ info = {
3286
+ id: config.id,
3287
+ displayName: config.displayName,
3288
+ defaultModel: config.defaultModel,
3289
+ apiKeyEnvVar: config.apiKeyEnvVar,
3290
+ requiresApiKey: config.requiresApiKey ?? true,
3291
+ baseUrl: config.baseUrl,
3292
+ models: config.models
3293
+ };
3354
3294
  };
3295
+ }
3296
+
3297
+ // src/providers/zhipu.ts
3298
+ var ZHIPU_CONFIG = {
3299
+ id: "zhipu",
3300
+ displayName: "Zhipu (GLM)",
3301
+ defaultModel: "glm-4.6",
3302
+ apiKeyEnvVar: "AICLI_API_KEY_ZHIPU",
3303
+ baseUrl: "https://open.bigmodel.cn/api/paas/v4",
3304
+ defaultTimeout: 3e5,
3305
+ models: [
3306
+ { id: "glm-5.2", displayName: "GLM-5.2 (2026-06 Flagship, 1M, Coding)", contextWindow: 1048576, supportsStreaming: true, supportsThinking: true },
3307
+ { id: "glm-5v-turbo", displayName: "GLM-5V-Turbo (Multimodal Vision + Coding)", contextWindow: 202752, supportsStreaming: true },
3308
+ { id: "glm-5.1", displayName: "GLM-5.1 (2026 Flagship, 200K, Agent+Code)", contextWindow: 204800, supportsStreaming: true, supportsThinking: true },
3309
+ { id: "glm-5.1-reasoning", displayName: "GLM-5.1 Reasoning (Deep Thinking)", contextWindow: 204800, supportsStreaming: true, supportsThinking: true },
3310
+ { id: "glm-5.1-air", displayName: "GLM-5.1 Air (Lightweight 5.1)", contextWindow: 204800, supportsStreaming: true, supportsThinking: true },
3311
+ { id: "glm-5", displayName: "GLM-5 (Flagship, Deep Thinking)", contextWindow: 131072, supportsStreaming: true, supportsThinking: true },
3312
+ { id: "glm-4.6", displayName: "GLM-4.6 (200K, \u4E2D\u6587\u5199\u4F5C\u63A8\u8350)", contextWindow: 204800, supportsStreaming: true }
3313
+ ]
3355
3314
  };
3315
+ var ZhipuProvider = createStaticProviderClass(ZHIPU_CONFIG);
3356
3316
 
3357
3317
  // src/providers/kimi.ts
3358
3318
  var KIMI_XML_REMINDER = `
@@ -3519,242 +3479,81 @@ var KimiProvider = class _KimiProvider extends OpenAICompatibleProvider {
3519
3479
  };
3520
3480
 
3521
3481
  // src/providers/minimax.ts
3522
- var MiniMaxProvider = class extends OpenAICompatibleProvider {
3523
- defaultBaseUrl = "https://api.minimaxi.com/v1";
3524
- info = {
3525
- id: "minimax",
3526
- displayName: "MiniMax (\u6D77\u87BA)",
3527
- defaultModel: "MiniMax-M3",
3528
- apiKeyEnvVar: "AICLI_API_KEY_MINIMAX",
3529
- requiresApiKey: true,
3530
- baseUrl: this.defaultBaseUrl,
3531
- models: [
3532
- {
3533
- id: "MiniMax-M3",
3534
- displayName: "MiniMax M3\uFF08\u65D7\u8230\uFF0C1M \u4E0A\u4E0B\u6587\uFF09",
3535
- contextWindow: 1e6,
3536
- supportsStreaming: true
3537
- },
3538
- {
3539
- id: "MiniMax-M2.7",
3540
- displayName: "MiniMax M2.7",
3541
- contextWindow: 1e6,
3542
- supportsStreaming: true
3543
- },
3544
- {
3545
- id: "MiniMax-M2.7-highspeed",
3546
- displayName: "MiniMax M2.7 Highspeed",
3547
- contextWindow: 1e6,
3548
- supportsStreaming: true
3549
- },
3550
- {
3551
- id: "MiniMax-M2.5",
3552
- displayName: "MiniMax M2.5",
3553
- contextWindow: 1e6,
3554
- supportsStreaming: true
3555
- },
3556
- {
3557
- id: "MiniMax-M2.5-highspeed",
3558
- displayName: "MiniMax M2.5 Highspeed",
3559
- contextWindow: 1e6,
3560
- supportsStreaming: true
3561
- }
3562
- ]
3563
- };
3482
+ var MINIMAX_CONFIG = {
3483
+ id: "minimax",
3484
+ displayName: "MiniMax (\u6D77\u87BA)",
3485
+ defaultModel: "MiniMax-M3",
3486
+ apiKeyEnvVar: "AICLI_API_KEY_MINIMAX",
3487
+ baseUrl: "https://api.minimaxi.com/v1",
3488
+ models: [
3489
+ { id: "MiniMax-M3", displayName: "MiniMax M3\uFF08\u65D7\u8230\uFF0C1M \u4E0A\u4E0B\u6587\uFF09", contextWindow: 1e6, supportsStreaming: true },
3490
+ { id: "MiniMax-M2.7", displayName: "MiniMax M2.7", contextWindow: 1e6, supportsStreaming: true },
3491
+ { id: "MiniMax-M2.7-highspeed", displayName: "MiniMax M2.7 Highspeed", contextWindow: 1e6, supportsStreaming: true },
3492
+ { id: "MiniMax-M2.5", displayName: "MiniMax M2.5", contextWindow: 1e6, supportsStreaming: true },
3493
+ { id: "MiniMax-M2.5-highspeed", displayName: "MiniMax M2.5 Highspeed", contextWindow: 1e6, supportsStreaming: true }
3494
+ ]
3564
3495
  };
3496
+ var MiniMaxProvider = createStaticProviderClass(MINIMAX_CONFIG);
3565
3497
 
3566
3498
  // src/providers/qwen.ts
3567
- var QwenProvider = class extends OpenAICompatibleProvider {
3568
- defaultBaseUrl = "https://dashscope.aliyuncs.com/compatible-mode/v1";
3569
- info = {
3570
- id: "qwen",
3571
- displayName: "Qwen (Alibaba Cloud)",
3572
- defaultModel: "qwen-plus",
3573
- apiKeyEnvVar: "AICLI_API_KEY_QWEN",
3574
- requiresApiKey: true,
3575
- baseUrl: this.defaultBaseUrl,
3576
- models: [
3577
- {
3578
- id: "qwen-plus",
3579
- displayName: "Qwen Plus",
3580
- contextWindow: 131072,
3581
- supportsStreaming: true
3582
- },
3583
- {
3584
- id: "qwen-max",
3585
- displayName: "Qwen Max",
3586
- contextWindow: 131072,
3587
- supportsStreaming: true
3588
- },
3589
- {
3590
- id: "qwen-turbo",
3591
- displayName: "Qwen Turbo",
3592
- contextWindow: 131072,
3593
- supportsStreaming: true
3594
- },
3595
- {
3596
- id: "qwen-coder-plus",
3597
- displayName: "Qwen Coder Plus",
3598
- contextWindow: 131072,
3599
- supportsStreaming: true
3600
- }
3601
- ]
3602
- };
3499
+ var QWEN_CONFIG = {
3500
+ id: "qwen",
3501
+ displayName: "Qwen (Alibaba Cloud)",
3502
+ defaultModel: "qwen-plus",
3503
+ apiKeyEnvVar: "AICLI_API_KEY_QWEN",
3504
+ baseUrl: "https://dashscope.aliyuncs.com/compatible-mode/v1",
3505
+ models: [
3506
+ { id: "qwen-plus", displayName: "Qwen Plus", contextWindow: 131072, supportsStreaming: true },
3507
+ { id: "qwen-max", displayName: "Qwen Max", contextWindow: 131072, supportsStreaming: true },
3508
+ { id: "qwen-turbo", displayName: "Qwen Turbo", contextWindow: 131072, supportsStreaming: true },
3509
+ { id: "qwen-coder-plus", displayName: "Qwen Coder Plus", contextWindow: 131072, supportsStreaming: true }
3510
+ ]
3603
3511
  };
3512
+ var QwenProvider = createStaticProviderClass(QWEN_CONFIG);
3604
3513
 
3605
3514
  // src/providers/openai.ts
3606
- var OpenAIProvider = class extends OpenAICompatibleProvider {
3607
- defaultBaseUrl = "https://api.openai.com/v1";
3608
- info = {
3609
- id: "openai",
3610
- displayName: "OpenAI",
3611
- defaultModel: "gpt-5.4",
3612
- apiKeyEnvVar: "AICLI_API_KEY_OPENAI",
3613
- requiresApiKey: true,
3614
- baseUrl: this.defaultBaseUrl,
3615
- models: [
3616
- // GPT-5.4 系列(最新旗舰,1.05M 上下文)
3617
- {
3618
- id: "gpt-5.4",
3619
- displayName: "GPT-5.4",
3620
- contextWindow: 105e4,
3621
- supportsStreaming: true
3622
- },
3623
- {
3624
- id: "gpt-5.4-pro",
3625
- displayName: "GPT-5.4 Pro",
3626
- contextWindow: 105e4,
3627
- supportsStreaming: true
3628
- },
3629
- // GPT-5 系列(400K 上下文)
3630
- {
3631
- id: "gpt-5",
3632
- displayName: "GPT-5",
3633
- contextWindow: 4e5,
3634
- supportsStreaming: true
3635
- },
3636
- {
3637
- id: "gpt-5-mini",
3638
- displayName: "GPT-5 Mini",
3639
- contextWindow: 4e5,
3640
- supportsStreaming: true
3641
- },
3642
- {
3643
- id: "gpt-5-nano",
3644
- displayName: "GPT-5 Nano",
3645
- contextWindow: 4e5,
3646
- supportsStreaming: true
3647
- },
3648
- // GPT-4.1 系列(1M 上下文)
3649
- {
3650
- id: "gpt-4.1",
3651
- displayName: "GPT-4.1",
3652
- contextWindow: 1048576,
3653
- supportsStreaming: true
3654
- },
3655
- {
3656
- id: "gpt-4.1-mini",
3657
- displayName: "GPT-4.1 Mini",
3658
- contextWindow: 1048576,
3659
- supportsStreaming: true
3660
- },
3661
- {
3662
- id: "gpt-4.1-nano",
3663
- displayName: "GPT-4.1 Nano",
3664
- contextWindow: 1048576,
3665
- supportsStreaming: true
3666
- },
3667
- // 推理模型(200K 上下文)
3668
- {
3669
- id: "o3",
3670
- displayName: "o3",
3671
- contextWindow: 2e5,
3672
- supportsStreaming: true
3673
- },
3674
- {
3675
- id: "o4-mini",
3676
- displayName: "o4 Mini",
3677
- contextWindow: 2e5,
3678
- supportsStreaming: true
3679
- }
3680
- ]
3681
- };
3515
+ var OPENAI_CONFIG = {
3516
+ id: "openai",
3517
+ displayName: "OpenAI",
3518
+ defaultModel: "gpt-5.4",
3519
+ apiKeyEnvVar: "AICLI_API_KEY_OPENAI",
3520
+ baseUrl: "https://api.openai.com/v1",
3521
+ models: [
3522
+ { id: "gpt-5.4", displayName: "GPT-5.4", contextWindow: 105e4, supportsStreaming: true },
3523
+ { id: "gpt-5.4-pro", displayName: "GPT-5.4 Pro", contextWindow: 105e4, supportsStreaming: true },
3524
+ { id: "gpt-5", displayName: "GPT-5", contextWindow: 4e5, supportsStreaming: true },
3525
+ { id: "gpt-5-mini", displayName: "GPT-5 Mini", contextWindow: 4e5, supportsStreaming: true },
3526
+ { id: "gpt-5-nano", displayName: "GPT-5 Nano", contextWindow: 4e5, supportsStreaming: true },
3527
+ { id: "gpt-4.1", displayName: "GPT-4.1", contextWindow: 1048576, supportsStreaming: true },
3528
+ { id: "gpt-4.1-mini", displayName: "GPT-4.1 Mini", contextWindow: 1048576, supportsStreaming: true },
3529
+ { id: "gpt-4.1-nano", displayName: "GPT-4.1 Nano", contextWindow: 1048576, supportsStreaming: true },
3530
+ { id: "o3", displayName: "o3", contextWindow: 2e5, supportsStreaming: true },
3531
+ { id: "o4-mini", displayName: "o4 Mini", contextWindow: 2e5, supportsStreaming: true }
3532
+ ]
3682
3533
  };
3534
+ var OpenAIProvider = createStaticProviderClass(OPENAI_CONFIG);
3683
3535
 
3684
3536
  // src/providers/openrouter.ts
3685
- var OpenRouterProvider = class extends OpenAICompatibleProvider {
3686
- defaultBaseUrl = "https://openrouter.ai/api/v1";
3687
- info = {
3688
- id: "openrouter",
3689
- displayName: "OpenRouter",
3690
- defaultModel: "anthropic/claude-sonnet-4",
3691
- apiKeyEnvVar: "AICLI_API_KEY_OPENROUTER",
3692
- requiresApiKey: true,
3693
- baseUrl: this.defaultBaseUrl,
3694
- models: [
3695
- {
3696
- id: "anthropic/claude-opus-4",
3697
- displayName: "Claude Opus 4",
3698
- contextWindow: 2e5,
3699
- supportsStreaming: true
3700
- },
3701
- {
3702
- id: "anthropic/claude-sonnet-4",
3703
- displayName: "Claude Sonnet 4",
3704
- contextWindow: 2e5,
3705
- supportsStreaming: true
3706
- },
3707
- {
3708
- id: "anthropic/claude-haiku-4",
3709
- displayName: "Claude Haiku 4",
3710
- contextWindow: 2e5,
3711
- supportsStreaming: true
3712
- },
3713
- {
3714
- id: "openai/gpt-5.4",
3715
- displayName: "GPT-5.4",
3716
- contextWindow: 105e4,
3717
- supportsStreaming: true
3718
- },
3719
- {
3720
- id: "google/gemini-2.5-pro",
3721
- displayName: "Gemini 2.5 Pro",
3722
- contextWindow: 1048576,
3723
- supportsStreaming: true
3724
- },
3725
- {
3726
- id: "google/gemini-2.5-flash",
3727
- displayName: "Gemini 2.5 Flash",
3728
- contextWindow: 1048576,
3729
- supportsStreaming: true
3730
- },
3731
- {
3732
- id: "meta-llama/llama-4-maverick",
3733
- displayName: "Llama 4 Maverick",
3734
- contextWindow: 1048576,
3735
- supportsStreaming: true
3736
- },
3737
- {
3738
- id: "meta-llama/llama-4-scout",
3739
- displayName: "Llama 4 Scout",
3740
- contextWindow: 512e3,
3741
- supportsStreaming: true
3742
- },
3743
- {
3744
- id: "qwen/qwen3-coder",
3745
- displayName: "Qwen3 Coder",
3746
- contextWindow: 262144,
3747
- supportsStreaming: true
3748
- },
3749
- {
3750
- id: "mistralai/mistral-large",
3751
- displayName: "Mistral Large",
3752
- contextWindow: 131072,
3753
- supportsStreaming: true
3754
- }
3755
- ]
3756
- };
3537
+ var OPENROUTER_CONFIG = {
3538
+ id: "openrouter",
3539
+ displayName: "OpenRouter",
3540
+ defaultModel: "anthropic/claude-sonnet-4",
3541
+ apiKeyEnvVar: "AICLI_API_KEY_OPENROUTER",
3542
+ baseUrl: "https://openrouter.ai/api/v1",
3543
+ models: [
3544
+ { id: "anthropic/claude-opus-4", displayName: "Claude Opus 4", contextWindow: 2e5, supportsStreaming: true },
3545
+ { id: "anthropic/claude-sonnet-4", displayName: "Claude Sonnet 4", contextWindow: 2e5, supportsStreaming: true },
3546
+ { id: "anthropic/claude-haiku-4", displayName: "Claude Haiku 4", contextWindow: 2e5, supportsStreaming: true },
3547
+ { id: "openai/gpt-5.4", displayName: "GPT-5.4", contextWindow: 105e4, supportsStreaming: true },
3548
+ { id: "google/gemini-2.5-pro", displayName: "Gemini 2.5 Pro", contextWindow: 1048576, supportsStreaming: true },
3549
+ { id: "google/gemini-2.5-flash", displayName: "Gemini 2.5 Flash", contextWindow: 1048576, supportsStreaming: true },
3550
+ { id: "meta-llama/llama-4-maverick", displayName: "Llama 4 Maverick", contextWindow: 1048576, supportsStreaming: true },
3551
+ { id: "meta-llama/llama-4-scout", displayName: "Llama 4 Scout", contextWindow: 512e3, supportsStreaming: true },
3552
+ { id: "qwen/qwen3-coder", displayName: "Qwen3 Coder", contextWindow: 262144, supportsStreaming: true },
3553
+ { id: "mistralai/mistral-large", displayName: "Mistral Large", contextWindow: 131072, supportsStreaming: true }
3554
+ ]
3757
3555
  };
3556
+ var OpenRouterProvider = createStaticProviderClass(OPENROUTER_CONFIG);
3758
3557
 
3759
3558
  // src/providers/ollama.ts
3760
3559
  var OllamaProvider = class extends OpenAICompatibleProvider {
@@ -4152,6 +3951,8 @@ var Session = class _Session {
4152
3951
  * 持久化在 toJSON / fromJSON 中,重启后不会重复请求。
4153
3952
  */
4154
3953
  titleAiGenerated;
3954
+ /** P1-PERF-03: 脏标记 — 任何修改操作设为 true,save() 后归零;避免大 session 无变更时的全量序列化写盘 */
3955
+ dirty = false;
4155
3956
  tokenUsage = {
4156
3957
  inputTokens: 0,
4157
3958
  outputTokens: 0,
@@ -4194,10 +3995,12 @@ var Session = class _Session {
4194
3995
  this.provider = provider;
4195
3996
  this.model = model;
4196
3997
  this.updated = /* @__PURE__ */ new Date();
3998
+ this.dirty = true;
4197
3999
  }
4198
4000
  addMessage(message) {
4199
4001
  this.messages.push(message);
4200
4002
  this.updated = /* @__PURE__ */ new Date();
4003
+ this.dirty = true;
4201
4004
  if (!this.title && message.role === "user") {
4202
4005
  this.title = getContentText(message.content).slice(0, 50).replace(/\n/g, " ");
4203
4006
  }
@@ -4207,6 +4010,7 @@ var Session = class _Session {
4207
4010
  this.tokenUsage.outputTokens += usage.outputTokens;
4208
4011
  this.tokenUsage.cacheCreationTokens += usage.cacheCreationTokens ?? 0;
4209
4012
  this.tokenUsage.cacheReadTokens += usage.cacheReadTokens ?? 0;
4013
+ this.dirty = true;
4210
4014
  }
4211
4015
  clear() {
4212
4016
  this.messages = [];
@@ -4219,6 +4023,7 @@ var Session = class _Session {
4219
4023
  cacheReadTokens: 0
4220
4024
  };
4221
4025
  this.updated = /* @__PURE__ */ new Date();
4026
+ this.dirty = true;
4222
4027
  }
4223
4028
  /**
4224
4029
  * 上下文压缩:用摘要消息替换旧消息,保留最近 keepLast 条。
@@ -4244,6 +4049,7 @@ var Session = class _Session {
4244
4049
  const removedCount = cutIndex;
4245
4050
  this.messages = [summaryMsg, ackMsg, ...preserved];
4246
4051
  this.updated = /* @__PURE__ */ new Date();
4052
+ this.dirty = true;
4247
4053
  return removedCount;
4248
4054
  }
4249
4055
  /** 在当前消息位置创建检查点 */
@@ -4254,6 +4060,7 @@ var Session = class _Session {
4254
4060
  messageIndex: this.messages.length,
4255
4061
  timestamp: /* @__PURE__ */ new Date()
4256
4062
  });
4063
+ this.dirty = true;
4257
4064
  }
4258
4065
  /** 恢复到指定检查点:截断消息到检查点位置,移除后续检查点 */
4259
4066
  restoreCheckpoint(name) {
@@ -4262,6 +4069,7 @@ var Session = class _Session {
4262
4069
  this.messages = this.messages.slice(0, cp.messageIndex);
4263
4070
  this.checkpoints = this.checkpoints.filter((c) => c.messageIndex <= cp.messageIndex);
4264
4071
  this.updated = /* @__PURE__ */ new Date();
4072
+ this.dirty = true;
4265
4073
  return true;
4266
4074
  }
4267
4075
  listCheckpoints() {
@@ -4329,6 +4137,7 @@ var Session = class _Session {
4329
4137
  this.messages = _Session.cloneMessages(this.messages.slice(0, fromIndex));
4330
4138
  this.activeBranchId = id;
4331
4139
  this.updated = /* @__PURE__ */ new Date();
4140
+ this.dirty = true;
4332
4141
  return id;
4333
4142
  }
4334
4143
  /**
@@ -4346,6 +4155,7 @@ var Session = class _Session {
4346
4155
  this.messages = target;
4347
4156
  this.activeBranchId = id;
4348
4157
  this.updated = /* @__PURE__ */ new Date();
4158
+ this.dirty = true;
4349
4159
  return true;
4350
4160
  }
4351
4161
  /**
@@ -4370,6 +4180,7 @@ var Session = class _Session {
4370
4180
  this.branches.splice(idx, 1);
4371
4181
  this._inactiveBranchMessages.delete(id);
4372
4182
  this.updated = /* @__PURE__ */ new Date();
4183
+ this.dirty = true;
4373
4184
  return true;
4374
4185
  }
4375
4186
  /** Rename a branch (affects only display title). */
@@ -4378,6 +4189,7 @@ var Session = class _Session {
4378
4189
  if (!b) return false;
4379
4190
  b.title = newTitle;
4380
4191
  this.updated = /* @__PURE__ */ new Date();
4192
+ this.dirty = true;
4381
4193
  return true;
4382
4194
  }
4383
4195
  /**
@@ -4460,6 +4272,7 @@ var Session = class _Session {
4460
4272
  };
4461
4273
  this.messages.push(copy);
4462
4274
  this.updated = /* @__PURE__ */ new Date();
4275
+ this.dirty = true;
4463
4276
  return copy;
4464
4277
  }
4465
4278
  getMeta() {
@@ -4552,6 +4365,7 @@ var Session = class _Session {
4552
4365
  });
4553
4366
  forked.checkpoints = original.checkpoints.filter((c) => c.messageIndex <= clampedCount).map((c) => ({ ...c, timestamp: new Date(c.timestamp.getTime()) }));
4554
4367
  forked.updated = /* @__PURE__ */ new Date();
4368
+ forked.dirty = true;
4555
4369
  return forked;
4556
4370
  }
4557
4371
  /**
@@ -4631,6 +4445,7 @@ var Session = class _Session {
4631
4445
  }
4632
4446
  }
4633
4447
  }
4448
+ session.dirty = false;
4634
4449
  return session;
4635
4450
  }
4636
4451
  };
@@ -4694,8 +4509,10 @@ var SessionManager = class {
4694
4509
  clearCurrent() {
4695
4510
  this._current = null;
4696
4511
  }
4697
- async save() {
4512
+ /** P1-PERF-03: `force` 跳过脏检查(用于进程退出、fork 等必须落盘场景) */
4513
+ async save(force = false) {
4698
4514
  if (!this._current) return;
4515
+ if (!force && !this._current.dirty) return;
4699
4516
  mkdirSync3(this.historyDir, { recursive: true });
4700
4517
  const filePath = join3(this.historyDir, `${this._current.id}.json`);
4701
4518
  const raw = this._current.toJSON();
@@ -4703,6 +4520,7 @@ var SessionManager = class {
4703
4520
  const { value: payload, hits } = redactJson(raw, opts);
4704
4521
  this.lastRedactionHits = hits.length;
4705
4522
  atomicWriteFileSync(filePath, JSON.stringify(payload, null, 2));
4523
+ this._current.dirty = false;
4706
4524
  }
4707
4525
  loadSession(id) {
4708
4526
  const filePath = join3(this.historyDir, `${id}.json`);
@@ -4843,10 +4661,10 @@ var SessionManager = class {
4843
4661
  if (!this._current) {
4844
4662
  throw new Error("No active session to fork");
4845
4663
  }
4846
- await this.save();
4664
+ await this.save(true);
4847
4665
  const forked = Session.fork(this._current, uuidv4(), messageCount, title);
4848
4666
  this._current = forked;
4849
- await this.save();
4667
+ await this.save(true);
4850
4668
  return forked;
4851
4669
  }
4852
4670
  /**
@@ -5382,14 +5200,19 @@ Important rules:
5382
5200
  );
5383
5201
  }
5384
5202
  if (status !== 0 || timedOut) {
5385
- throw {
5386
- status,
5387
- signal: null,
5388
- code: timedOut ? "ETIMEDOUT" : void 0,
5389
- stdout: Buffer.from(stdout, "utf-8"),
5390
- stderr: Buffer.from(stderr, "utf-8"),
5391
- message: timedOut ? "ETIMEDOUT" : `exit ${status}`
5392
- };
5203
+ const poolStdout = (stdout ?? "").trim();
5204
+ const poolStderr = (stderr ?? "").trim();
5205
+ const combined = [poolStdout, poolStderr].filter(Boolean).join("\n");
5206
+ const hint = buildErrorHint(command, combined);
5207
+ throw new ToolError(
5208
+ "bash",
5209
+ `Exit code ${status}:
5210
+ ${combined || `exit ${status}`}
5211
+
5212
+ ` + (hint ? `${hint}
5213
+
5214
+ ` : "") + `[Command failed. Report this error to the user. Do not retry with variant commands.]`
5215
+ );
5393
5216
  }
5394
5217
  pushBashUndoEntries(beforeSnapshot, parsedTargetsBefore, effectiveCwd);
5395
5218
  updateCwdFromCommand(command, effectiveCwd);
@@ -7313,7 +7136,7 @@ var ToolExecutor = class {
7313
7136
  runLifecycleHooks(this.hookConfig, "PostToolUse", { tool: call.name, status: "ok" }, { configDir: this.hookConfigDir });
7314
7137
  return { callId: call.id, content, isError: false };
7315
7138
  } catch (err) {
7316
- const message = err instanceof Error ? err.message : String(err);
7139
+ const message = err instanceof Error ? err.message : err && typeof err === "object" && "message" in err ? String(err.message) : String(err);
7317
7140
  this.printToolResult(call.name, message, true, false);
7318
7141
  runHook(this.hookConfig?.postToolExecution, { tool: call.name, status: "error" });
7319
7142
  runLifecycleHooks(this.hookConfig, "PostToolUse", { tool: call.name, status: "error", error: message }, { configDir: this.hookConfigDir });
@@ -7358,7 +7181,7 @@ var ToolExecutor = class {
7358
7181
  runLifecycleHooks(this.hookConfig, "PostToolUse", { tool: call.name, status: "ok" }, { configDir: this.hookConfigDir });
7359
7182
  return { callId: call.id, content, isError: false };
7360
7183
  } catch (err) {
7361
- const message = err instanceof Error ? err.message : String(err);
7184
+ const message = err instanceof Error ? err.message : err && typeof err === "object" && "message" in err ? String(err.message) : String(err);
7362
7185
  this.printToolResult(call.name, message, true, false);
7363
7186
  runHook(this.hookConfig?.postToolExecution, { tool: call.name, status: "error" });
7364
7187
  runLifecycleHooks(this.hookConfig, "PostToolUse", { tool: call.name, status: "error", error: message }, { configDir: this.hookConfigDir });
@@ -7379,7 +7202,7 @@ var ToolExecutor = class {
7379
7202
  runLifecycleHooks(this.hookConfig, "PostToolUse", { tool: call.name, status: "ok" }, { configDir: this.hookConfigDir });
7380
7203
  return { callId: call.id, content, isError: false };
7381
7204
  } catch (err) {
7382
- const message = err instanceof Error ? err.message : String(err);
7205
+ const message = err instanceof Error ? err.message : err && typeof err === "object" && "message" in err ? String(err.message) : String(err);
7383
7206
  this.printToolResult(call.name, message, true, false);
7384
7207
  runHook(this.hookConfig?.postToolExecution, { tool: call.name, status: "error" });
7385
7208
  runLifecycleHooks(this.hookConfig, "PostToolUse", { tool: call.name, status: "error", error: message }, { configDir: this.hookConfigDir });
@@ -7419,7 +7242,7 @@ var ToolExecutor = class {
7419
7242
  runLifecycleHooks(this.hookConfig, "PostToolUse", { tool: call.name, status: "ok" }, { configDir: this.hookConfigDir });
7420
7243
  return { callId: call.id, content, isError: false };
7421
7244
  } catch (err) {
7422
- const message = err instanceof Error ? err.message : String(err);
7245
+ const message = err instanceof Error ? err.message : err && typeof err === "object" && "message" in err ? String(err.message) : String(err);
7423
7246
  this.printToolResult(call.name, message, true, false);
7424
7247
  runHook(this.hookConfig?.postToolExecution, { tool: call.name, status: "error" });
7425
7248
  runLifecycleHooks(this.hookConfig, "PostToolUse", { tool: call.name, status: "error", error: message }, { configDir: this.hookConfigDir });
@@ -7505,7 +7328,7 @@ var ToolExecutor = class {
7505
7328
  this.printToolResult(call.name, rawContent, false, wasTruncated);
7506
7329
  results[i] = { callId: call.id, content, isError: false };
7507
7330
  } catch (err) {
7508
- const message = err instanceof Error ? err.message : String(err);
7331
+ const message = err instanceof Error ? err.message : err && typeof err === "object" && "message" in err ? String(err.message) : String(err);
7509
7332
  this.printToolResult(call.name, message, true, false);
7510
7333
  results[i] = { callId: call.id, content: message, isError: true };
7511
7334
  }
@@ -9867,7 +9690,6 @@ function saveMemoryEntries(configDir, entries) {
9867
9690
  mkdirSync8(configDir, { recursive: true });
9868
9691
  const jsonl = entries.map((entry) => JSON.stringify(entry)).join("\n");
9869
9692
  atomicWriteFileSync(memoryStorePath(configDir), jsonl ? jsonl + "\n" : "");
9870
- syncLegacyMarkdown(configDir, entries);
9871
9693
  }
9872
9694
  function isMemoryExpired(entry, at = /* @__PURE__ */ new Date()) {
9873
9695
  return Boolean(entry.expiresAt && Date.parse(entry.expiresAt) <= at.getTime());
@@ -9938,25 +9760,6 @@ function findUnique(entries, idPrefix) {
9938
9760
  if (matches.length > 1) throw new Error(`memory id is ambiguous: ${idPrefix}`);
9939
9761
  return matches[0];
9940
9762
  }
9941
- function syncLegacyMarkdown(configDir, entries = loadMemoryEntries(configDir)) {
9942
- mkdirSync8(dirname6(memoryMarkdownPath(configDir)), { recursive: true });
9943
- const active = entries.filter((entry) => entry.approved && !isMemoryExpired(entry));
9944
- const markdown = active.map((entry) => {
9945
- const date = entry.createdAt.replace("T", " ").slice(0, 19);
9946
- const source = [
9947
- `id:${entry.id.slice(0, 8)}`,
9948
- `scope:${entry.scope}`,
9949
- entry.sourceSession ? `session:${entry.sourceSession.slice(0, 8)}` : "",
9950
- entry.sourceProject ? `project:${entry.sourceProject}` : "",
9951
- `sensitivity:${entry.sensitivity}`
9952
- ].filter(Boolean).join(" \xB7 ");
9953
- return `## ${date}
9954
- <!-- ${source} -->
9955
- ${entry.content}
9956
- `;
9957
- }).join("\n");
9958
- atomicWriteFileSync(memoryMarkdownPath(configDir), markdown);
9959
- }
9960
9763
  function formatMemoryForPrompt(configDir, cwd = process.cwd()) {
9961
9764
  const entries = listMemoryEntries(configDir, { cwd }).filter((entry) => entry.approved && !isMemoryExpired(entry));
9962
9765
  if (entries.length === 0) return null;
@@ -13360,7 +13163,7 @@ var ToolExecutorWeb = class _ToolExecutorWeb {
13360
13163
  runLifecycleHooks(this.hookConfig, "PostToolUse", { tool: call.name, status: "ok" }, { configDir: this.hookConfigDir });
13361
13164
  return { callId: call.id, content, isError: false };
13362
13165
  } catch (err) {
13363
- const message = err instanceof Error ? err.message : String(err);
13166
+ const message = err instanceof Error ? err.message : err && typeof err === "object" && "message" in err ? String(err.message) : String(err);
13364
13167
  this.sendToolCallResult(call, message, true);
13365
13168
  runHook(this.hookConfig?.postToolExecution, { tool: call.name, status: "error" });
13366
13169
  runLifecycleHooks(this.hookConfig, "PostToolUse", { tool: call.name, status: "error", error: message }, { configDir: this.hookConfigDir });
@@ -13399,7 +13202,7 @@ var ToolExecutorWeb = class _ToolExecutorWeb {
13399
13202
  runLifecycleHooks(this.hookConfig, "PostToolUse", { tool: call.name, status: "ok" }, { configDir: this.hookConfigDir });
13400
13203
  return { callId: call.id, content, isError: false };
13401
13204
  } catch (err) {
13402
- const message = err instanceof Error ? err.message : String(err);
13205
+ const message = err instanceof Error ? err.message : err && typeof err === "object" && "message" in err ? String(err.message) : String(err);
13403
13206
  this.sendToolCallResult(call, message, true);
13404
13207
  runHook(this.hookConfig?.postToolExecution, { tool: call.name, status: "error" });
13405
13208
  runLifecycleHooks(this.hookConfig, "PostToolUse", { tool: call.name, status: "error", error: message }, { configDir: this.hookConfigDir });
@@ -13416,7 +13219,7 @@ var ToolExecutorWeb = class _ToolExecutorWeb {
13416
13219
  runLifecycleHooks(this.hookConfig, "PostToolUse", { tool: call.name, status: "ok" }, { configDir: this.hookConfigDir });
13417
13220
  return { callId: call.id, content, isError: false };
13418
13221
  } catch (err) {
13419
- const message = err instanceof Error ? err.message : String(err);
13222
+ const message = err instanceof Error ? err.message : err && typeof err === "object" && "message" in err ? String(err.message) : String(err);
13420
13223
  this.sendToolCallResult(call, message, true);
13421
13224
  runHook(this.hookConfig?.postToolExecution, { tool: call.name, status: "error" });
13422
13225
  runLifecycleHooks(this.hookConfig, "PostToolUse", { tool: call.name, status: "error", error: message }, { configDir: this.hookConfigDir });
@@ -13440,7 +13243,7 @@ var ToolExecutorWeb = class _ToolExecutorWeb {
13440
13243
  runLifecycleHooks(this.hookConfig, "PostToolUse", { tool: call.name, status: "ok" }, { configDir: this.hookConfigDir });
13441
13244
  return { callId: call.id, content, isError: false };
13442
13245
  } catch (err) {
13443
- const message = err instanceof Error ? err.message : String(err);
13246
+ const message = err instanceof Error ? err.message : err && typeof err === "object" && "message" in err ? String(err.message) : String(err);
13444
13247
  this.sendToolCallResult(call, message, true);
13445
13248
  runHook(this.hookConfig?.postToolExecution, { tool: call.name, status: "error" });
13446
13249
  runLifecycleHooks(this.hookConfig, "PostToolUse", { tool: call.name, status: "error", error: message }, { configDir: this.hookConfigDir });
@@ -13503,7 +13306,7 @@ var ToolExecutorWeb = class _ToolExecutorWeb {
13503
13306
  this.sendToolCallResult(call, rawContent, false);
13504
13307
  results[i] = { callId: call.id, content, isError: false };
13505
13308
  } catch (err) {
13506
- const message = err instanceof Error ? err.message : String(err);
13309
+ const message = err instanceof Error ? err.message : err && typeof err === "object" && "message" in err ? String(err.message) : String(err);
13507
13310
  this.sendToolCallResult(call, message, true);
13508
13311
  results[i] = { callId: call.id, content: message, isError: true };
13509
13312
  }
@@ -15822,37 +15625,32 @@ async function handleRewind(args, ctx) {
15822
15625
  async function handleTools(_args, ctx) {
15823
15626
  ctx.sendToolsList();
15824
15627
  }
15825
- async function handlePlugins(_args, ctx) {
15826
- const configDir = ctx.config.getConfigDir();
15827
- const pluginsDir = join24(configDir, PLUGINS_DIR_NAME);
15828
- const pluginTools = ctx.toolRegistry.listPluginTools();
15829
- const pluginPackages = listInstalledPlugins(configDir);
15830
- const lines = [`\u{1F50C} **Plugins:**`, `Dir: ${pluginsDir}`, ""];
15831
- if (pluginTools.length === 0 && pluginPackages.length === 0) {
15832
- lines.push("No plugins loaded.");
15833
- lines.push("Use /plugin install <path>, /plugin trust <name>, then /plugin enable <name>.");
15834
- } else {
15835
- if (pluginPackages.length > 0) {
15836
- lines.push(`Package plugins (${pluginPackages.length}):`);
15837
- for (const p of pluginPackages) lines.push(` \u2022 ${p.name}@${p.manifest.version} \u2014 ${p.enabled ? "enabled" : "disabled"} / ${p.trusted ? "trusted" : "untrusted"}`);
15838
- lines.push("");
15839
- }
15840
- if (pluginTools.length > 0) {
15841
- lines.push(`Legacy JS plugin tools (${pluginTools.length}):`);
15842
- for (const t of pluginTools) lines.push(` \u2022 ${t.definition.name} \u2014 ${t.definition.description}`);
15843
- }
15844
- }
15845
- ctx.send({ type: "info", message: lines.join("\n") });
15846
- }
15847
15628
  async function handlePlugin(args, ctx) {
15848
15629
  const configDir = ctx.config.getConfigDir();
15849
15630
  const sub = args[0] ?? "list";
15850
15631
  try {
15851
15632
  if (sub === "list") {
15852
15633
  const plugins = listInstalledPlugins(configDir);
15853
- const lines = [`\u{1F50C} **Package Plugins**`, `Dir: ${pluginRoot(configDir)}`, ""];
15854
- if (plugins.length === 0) lines.push("No package plugins installed.");
15855
- for (const p of plugins) lines.push(` \u2022 ${p.name}@${p.manifest.version} \u2014 ${p.enabled ? "enabled" : "disabled"} / ${p.trusted ? "trusted" : "untrusted"}`);
15634
+ const pluginTools = ctx.toolRegistry.listPluginTools();
15635
+ const lines = ["\u{1F50C} **Plugins**", ""];
15636
+ if (plugins.length === 0 && pluginTools.length === 0) {
15637
+ lines.push("No plugins loaded.");
15638
+ lines.push(`Dir: ${pluginRoot(configDir)}`);
15639
+ lines.push("Use /plugin install <path>, /plugin trust <name>, then /plugin enable <name>.");
15640
+ } else {
15641
+ if (plugins.length > 0) {
15642
+ lines.push(`**Package plugins** (${plugins.length}):`);
15643
+ lines.push(`Dir: ${pluginRoot(configDir)}`);
15644
+ for (const p of plugins) lines.push(` \u2022 ${p.name}@${p.manifest.version} \u2014 ${p.enabled ? "enabled" : "disabled"} / ${p.trusted ? "trusted" : "untrusted"}`);
15645
+ lines.push("");
15646
+ }
15647
+ if (pluginTools.length > 0) {
15648
+ const legacyDir = join24(configDir, PLUGINS_DIR_NAME);
15649
+ lines.push(`**Legacy JS tools** (${pluginTools.length}):`);
15650
+ lines.push(`Dir: ${legacyDir}`);
15651
+ for (const t of pluginTools) lines.push(` \u2022 ${t.definition.name} \u2014 ${t.definition.description}`);
15652
+ }
15653
+ }
15856
15654
  ctx.send({ type: "info", message: lines.join("\n") });
15857
15655
  return;
15858
15656
  }
@@ -16068,7 +15866,7 @@ async function handleSecurityReview(args, ctx) {
16068
15866
  async function handleTest(args, ctx) {
16069
15867
  ctx.send({ type: "info", message: "\u{1F9EA} Running tests..." });
16070
15868
  try {
16071
- const { executeTests } = await import("./run-tests-7SGHDDHL.js");
15869
+ const { executeTests } = await import("./run-tests-M45ZJPR6.js");
16072
15870
  const argStr = args.join(" ").trim();
16073
15871
  let testArgs = {};
16074
15872
  if (argStr) {
@@ -16548,8 +16346,7 @@ async function handleHelp(_args, ctx) {
16548
16346
  " /scaffold <desc> \u2014 Generate project scaffolding with AI",
16549
16347
  " /add-dir [path|remove] \u2014 Add/remove directory from AI context",
16550
16348
  " /mcp [reconnect] \u2014 Show/manage MCP servers",
16551
- " /plugins \u2014 Show loaded plugins",
16552
- " /plugin <cmd> \u2014 Manage package plugins",
16349
+ " /plugin <cmd> \u2014 Manage plugins (list/install/enable/disable/inspect/trust)",
16553
16350
  " /commands \u2014 List custom commands",
16554
16351
  " /doctor \u2014 Health check (API keys, config, MCP)",
16555
16352
  " /bug \u2014 Generate bug report template",
@@ -16666,7 +16463,6 @@ var webCommandHandlers = {
16666
16463
  fork: handleFork,
16667
16464
  rewind: handleRewind,
16668
16465
  tools: handleTools,
16669
- plugins: handlePlugins,
16670
16466
  plugin: handlePlugin,
16671
16467
  mcp: handleMcp,
16672
16468
  skill: handleSkill,