jinzd-ai-cli 0.4.229 → 0.4.231

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-XZHTNJXJ.js → batch-FLMFMR3R.js} +3 -3
  2. package/dist/{chunk-DEHVRQWW.js → chunk-4KM53GLG.js} +1 -1
  3. package/dist/{chunk-PQLRX7US.js → chunk-5T746UEU.js} +4 -4
  4. package/dist/{chunk-EEQHP4GK.js → chunk-62R7CACG.js} +101 -302
  5. package/dist/{chunk-SJ36SUG7.js → chunk-75TAFSFZ.js} +2 -2
  6. package/dist/{chunk-AXIMNQSY.js → chunk-ADARC33O.js} +1 -1
  7. package/dist/{chunk-DMF6UHO6.js → chunk-FWAA3ARX.js} +14 -24
  8. package/dist/{chunk-QFOJ4GXC.js → chunk-NB7LR3TP.js} +4 -4
  9. package/dist/{chunk-TEXAIWUJ.js → chunk-TQPU3J4P.js} +1 -1
  10. package/dist/{chunk-QCGKCNBX.js → chunk-UOIUGBG2.js} +1 -1
  11. package/dist/{chunk-FEVOW3NQ.js → chunk-XTMHBOHG.js} +1 -1
  12. package/dist/{chunk-AEXWMIRE.js → chunk-YH657UWU.js} +1 -1
  13. package/dist/{chunk-B3POS7LB.js → chunk-ZOLZ6JPG.js} +1 -1
  14. package/dist/{chunk-QYQCCIBT.js → chunk-ZWU7FWHO.js} +22 -3
  15. package/dist/{ci-ZCVDKFXY.js → ci-SI2VXE4Q.js} +5 -5
  16. package/dist/{ci-format-CKXDFTN3.js → ci-format-SFTFN3SE.js} +2 -2
  17. package/dist/{constants-J2MSGNFA.js → constants-EOWAB3VR.js} +1 -1
  18. package/dist/{doctor-cli-3VNTECP2.js → doctor-cli-4YVKJESI.js} +5 -5
  19. package/dist/electron-server.js +157 -356
  20. package/dist/{hub-LIH5JEI7.js → hub-6IKXR32G.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-HY2QCVUY.js → pr-QJFFSYEU.js} +5 -5
  24. package/dist/{run-tests-QVXDTJ3O.js → run-tests-RZKUBZB4.js} +1 -1
  25. package/dist/{run-tests-WBGQI5V7.js → run-tests-ZBX476UL.js} +2 -2
  26. package/dist/{server-5RXWIX4I.js → server-4XGNHG6P.js} +4 -4
  27. package/dist/{server-LYTXYK6Y.js → server-6IDBCCJ2.js} +32 -39
  28. package/dist/{task-orchestrator-FA4KOVD2.js → task-orchestrator-UGKJ7UY4.js} +4 -4
  29. package/dist/{usage-EHV6YVGH.js → usage-2VGL3YWF.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-QCGKCNBX.js";
41
+ } from "./chunk-UOIUGBG2.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
  /**
@@ -6043,7 +5861,17 @@ Current working directory: ${process.cwd()}
6043
5861
  Please use list_dir to verify the file path and retry.`
6044
5862
  );
6045
5863
  }
6046
- const { size } = statSync3(normalizedPath);
5864
+ const st = statSync3(normalizedPath);
5865
+ if (st.isDirectory()) {
5866
+ const entries = readdirSync3(normalizedPath, { withFileTypes: true }).slice(0, 10);
5867
+ const listing = entries.map((e) => `${e.isDirectory() ? "\u{1F4C1}" : "\u{1F4C4}"} ${e.name}`).join("\n");
5868
+ return `[Directory: ${filePath}]
5869
+ This path is a directory, not a file. Use list_dir to browse it.
5870
+ ` + (listing ? `
5871
+ First 10 entries:
5872
+ ${listing}` : "");
5873
+ }
5874
+ const { size } = st;
6047
5875
  if (size > MAX_FILE_BYTES) {
6048
5876
  const mb = (size / 1024 / 1024).toFixed(1);
6049
5877
  return `[File too large: ${filePath} (${mb} MB)]
@@ -9872,7 +9700,6 @@ function saveMemoryEntries(configDir, entries) {
9872
9700
  mkdirSync8(configDir, { recursive: true });
9873
9701
  const jsonl = entries.map((entry) => JSON.stringify(entry)).join("\n");
9874
9702
  atomicWriteFileSync(memoryStorePath(configDir), jsonl ? jsonl + "\n" : "");
9875
- syncLegacyMarkdown(configDir, entries);
9876
9703
  }
9877
9704
  function isMemoryExpired(entry, at = /* @__PURE__ */ new Date()) {
9878
9705
  return Boolean(entry.expiresAt && Date.parse(entry.expiresAt) <= at.getTime());
@@ -9943,25 +9770,6 @@ function findUnique(entries, idPrefix) {
9943
9770
  if (matches.length > 1) throw new Error(`memory id is ambiguous: ${idPrefix}`);
9944
9771
  return matches[0];
9945
9772
  }
9946
- function syncLegacyMarkdown(configDir, entries = loadMemoryEntries(configDir)) {
9947
- mkdirSync8(dirname6(memoryMarkdownPath(configDir)), { recursive: true });
9948
- const active = entries.filter((entry) => entry.approved && !isMemoryExpired(entry));
9949
- const markdown = active.map((entry) => {
9950
- const date = entry.createdAt.replace("T", " ").slice(0, 19);
9951
- const source = [
9952
- `id:${entry.id.slice(0, 8)}`,
9953
- `scope:${entry.scope}`,
9954
- entry.sourceSession ? `session:${entry.sourceSession.slice(0, 8)}` : "",
9955
- entry.sourceProject ? `project:${entry.sourceProject}` : "",
9956
- `sensitivity:${entry.sensitivity}`
9957
- ].filter(Boolean).join(" \xB7 ");
9958
- return `## ${date}
9959
- <!-- ${source} -->
9960
- ${entry.content}
9961
- `;
9962
- }).join("\n");
9963
- atomicWriteFileSync(memoryMarkdownPath(configDir), markdown);
9964
- }
9965
9773
  function formatMemoryForPrompt(configDir, cwd = process.cwd()) {
9966
9774
  const entries = listMemoryEntries(configDir, { cwd }).filter((entry) => entry.approved && !isMemoryExpired(entry));
9967
9775
  if (entries.length === 0) return null;
@@ -15827,37 +15635,32 @@ async function handleRewind(args, ctx) {
15827
15635
  async function handleTools(_args, ctx) {
15828
15636
  ctx.sendToolsList();
15829
15637
  }
15830
- async function handlePlugins(_args, ctx) {
15831
- const configDir = ctx.config.getConfigDir();
15832
- const pluginsDir = join24(configDir, PLUGINS_DIR_NAME);
15833
- const pluginTools = ctx.toolRegistry.listPluginTools();
15834
- const pluginPackages = listInstalledPlugins(configDir);
15835
- const lines = [`\u{1F50C} **Plugins:**`, `Dir: ${pluginsDir}`, ""];
15836
- if (pluginTools.length === 0 && pluginPackages.length === 0) {
15837
- lines.push("No plugins loaded.");
15838
- lines.push("Use /plugin install <path>, /plugin trust <name>, then /plugin enable <name>.");
15839
- } else {
15840
- if (pluginPackages.length > 0) {
15841
- lines.push(`Package plugins (${pluginPackages.length}):`);
15842
- for (const p of pluginPackages) lines.push(` \u2022 ${p.name}@${p.manifest.version} \u2014 ${p.enabled ? "enabled" : "disabled"} / ${p.trusted ? "trusted" : "untrusted"}`);
15843
- lines.push("");
15844
- }
15845
- if (pluginTools.length > 0) {
15846
- lines.push(`Legacy JS plugin tools (${pluginTools.length}):`);
15847
- for (const t of pluginTools) lines.push(` \u2022 ${t.definition.name} \u2014 ${t.definition.description}`);
15848
- }
15849
- }
15850
- ctx.send({ type: "info", message: lines.join("\n") });
15851
- }
15852
15638
  async function handlePlugin(args, ctx) {
15853
15639
  const configDir = ctx.config.getConfigDir();
15854
15640
  const sub = args[0] ?? "list";
15855
15641
  try {
15856
15642
  if (sub === "list") {
15857
15643
  const plugins = listInstalledPlugins(configDir);
15858
- const lines = [`\u{1F50C} **Package Plugins**`, `Dir: ${pluginRoot(configDir)}`, ""];
15859
- if (plugins.length === 0) lines.push("No package plugins installed.");
15860
- for (const p of plugins) lines.push(` \u2022 ${p.name}@${p.manifest.version} \u2014 ${p.enabled ? "enabled" : "disabled"} / ${p.trusted ? "trusted" : "untrusted"}`);
15644
+ const pluginTools = ctx.toolRegistry.listPluginTools();
15645
+ const lines = ["\u{1F50C} **Plugins**", ""];
15646
+ if (plugins.length === 0 && pluginTools.length === 0) {
15647
+ lines.push("No plugins loaded.");
15648
+ lines.push(`Dir: ${pluginRoot(configDir)}`);
15649
+ lines.push("Use /plugin install <path>, /plugin trust <name>, then /plugin enable <name>.");
15650
+ } else {
15651
+ if (plugins.length > 0) {
15652
+ lines.push(`**Package plugins** (${plugins.length}):`);
15653
+ lines.push(`Dir: ${pluginRoot(configDir)}`);
15654
+ for (const p of plugins) lines.push(` \u2022 ${p.name}@${p.manifest.version} \u2014 ${p.enabled ? "enabled" : "disabled"} / ${p.trusted ? "trusted" : "untrusted"}`);
15655
+ lines.push("");
15656
+ }
15657
+ if (pluginTools.length > 0) {
15658
+ const legacyDir = join24(configDir, PLUGINS_DIR_NAME);
15659
+ lines.push(`**Legacy JS tools** (${pluginTools.length}):`);
15660
+ lines.push(`Dir: ${legacyDir}`);
15661
+ for (const t of pluginTools) lines.push(` \u2022 ${t.definition.name} \u2014 ${t.definition.description}`);
15662
+ }
15663
+ }
15861
15664
  ctx.send({ type: "info", message: lines.join("\n") });
15862
15665
  return;
15863
15666
  }
@@ -16073,7 +15876,7 @@ async function handleSecurityReview(args, ctx) {
16073
15876
  async function handleTest(args, ctx) {
16074
15877
  ctx.send({ type: "info", message: "\u{1F9EA} Running tests..." });
16075
15878
  try {
16076
- const { executeTests } = await import("./run-tests-QVXDTJ3O.js");
15879
+ const { executeTests } = await import("./run-tests-RZKUBZB4.js");
16077
15880
  const argStr = args.join(" ").trim();
16078
15881
  let testArgs = {};
16079
15882
  if (argStr) {
@@ -16553,8 +16356,7 @@ async function handleHelp(_args, ctx) {
16553
16356
  " /scaffold <desc> \u2014 Generate project scaffolding with AI",
16554
16357
  " /add-dir [path|remove] \u2014 Add/remove directory from AI context",
16555
16358
  " /mcp [reconnect] \u2014 Show/manage MCP servers",
16556
- " /plugins \u2014 Show loaded plugins",
16557
- " /plugin <cmd> \u2014 Manage package plugins",
16359
+ " /plugin <cmd> \u2014 Manage plugins (list/install/enable/disable/inspect/trust)",
16558
16360
  " /commands \u2014 List custom commands",
16559
16361
  " /doctor \u2014 Health check (API keys, config, MCP)",
16560
16362
  " /bug \u2014 Generate bug report template",
@@ -16671,7 +16473,6 @@ var webCommandHandlers = {
16671
16473
  fork: handleFork,
16672
16474
  rewind: handleRewind,
16673
16475
  tools: handleTools,
16674
- plugins: handlePlugins,
16675
16476
  plugin: handlePlugin,
16676
16477
  mcp: handleMcp,
16677
16478
  skill: handleSkill,