@zhushanwen/zcode-subagent-cli 0.5.0 → 0.6.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.
@@ -600,6 +600,7 @@ const os = require('node:os');
600
600
 
601
601
  const CLI_PATH = process.env.ZCODE_ENG_CLI_PATH;
602
602
  const V2_PATH = process.env.ZCODE_ENG_V2_CONFIG || path.join(os.homedir(), '.zcode', 'v2', 'config.json');
603
+ const PROVIDER_CONFIG_PATH = process.env.ZCODE_ENG_PROVIDER_CONFIG || path.join(os.homedir(), '.zcode', 'v2', 'provider_config.json');
603
604
  const CONFIG_PATH = path.join(os.homedir(), '.zcode', 'cli', 'config.json');
604
605
 
605
606
  // \u5408\u5E76\u5F62\u6001\uFF1A\u771F\u5B9E cli config \u539F\u6837\uFF08model/plugins/mcp/subagents \u7B49 worker \u7EE7\u627F\u9762\u4E0D\u53D8\uFF09
@@ -608,6 +609,10 @@ const CONFIG_PATH = path.join(os.homedir(), '.zcode', 'cli', 'config.json');
608
609
  // \u914D\u7F6E\uFF082026-08-25 \u4E8B\u6545\uFF1A\u6B8B\u7559\u65E7 key \u538B\u8FC7\u65B0\u51ED\u636E\u81F4 turn 0 401\uFF09\uFF0C\u6545\u4E0D\u53D6 real \u4F18\u5148\u3002
609
610
  // model.main \u7F3A\u5931\u65F6\u53EA\u4ECE v2 \u900F\u4F20\uFF08v2 \u4E5F\u6CA1\u6709\u5219\u4E0D\u4F2A\u9020\u2014\u2014CLI \u7F3A\u7701\u89E3\u6790\u81EA\u4F1A\u843D\u5230\u6CE8\u518C\u8868
610
611
  // \u53EF\u7528\u6A21\u578B\uFF1Bplan \u5BB6\u65CF id \u5DF2\u4E0D\u53EF\u7528\uFF0C\u4E0D\u518D\u515C\u5E95\u4F2A\u9020\uFF09\u3002
612
+ // [D3 \u987A\u5E26\u53D1\u73B0 6] provider_config.json\uFF08\u5F15\u64CE\u4FA7\u6A21\u578B\u6821\u9A8C\u6E90\uFF09\u8865\u6CE8\u5165\uFF1A\u4EC5\u5B58\u5728\u4E8E
613
+ // providerRules \u7684\u4E2A\u4EBA provider\uFF08v2 \u5B57\u5178\u672A\u7269\u5316\uFF09\u4E0D\u5728\u6CE8\u5165\u96C6 \u2192 app-server \u6CE8\u518C\u8868
614
+ // \u7F3A\u6761\u76EE\uFF0C\u663E\u5F0F\u6A21\u578B\u9996\u6D3E\u5373\u62A5\u300CProvider Registry \u4E2D\u4E0D\u5B58\u5728 Model\u300D\u3002\u4E3A\u5E26 apiKey+baseUrl
615
+ // \u4E14 v2/real \u5747\u7F3A\u5931\u7684 rule \u5408\u6210 cli-config \u6761\u76EE\uFF08\u5F62\u72B6\u7167\u6284\u73B0\u7F51\u4E2A\u4EBA\u6761\u76EE\uFF09\u3002
611
616
  // \u8FD4\u56DE null = \u65E0\u53EF\u6CE8\u5165\u51ED\u636E\uFF08v2 \u65E0 provider \u6761\u76EE\uFF09\u2014\u2014\u4E0D patch\uFF0C\u8BA9\u539F\u751F\u62A5\u9519\u900F\u51FA\u3002
612
617
  // \u8BFB\u6E90\u7ECF readOrig \u95F4\u63A5\u53D6\uFF1Apatch \u524D\u9996\u8C03 = fs.readFileSync \u672C\u4F53\uFF1Bpatch \u540E = \u539F\u51FD\u6570
613
618
  // \uFF08\u9632 patch \u540E\u7684\u9012\u5F52\u81EA\u8C03\u7528\uFF09\u3002
@@ -625,6 +630,7 @@ function injectedConfigText() {
625
630
  }
626
631
  return null;
627
632
  }
633
+ const realProviders = real.provider && typeof real.provider === 'object' ? real.provider : {};
628
634
  const v2Providers = v2.provider && typeof v2.provider === 'object' ? v2.provider : {};
629
635
  const hasKey = (entry) => entry && typeof entry === 'object'
630
636
  && entry.options && typeof entry.options.apiKey === 'string' && entry.options.apiKey !== '';
@@ -632,9 +638,60 @@ function injectedConfigText() {
632
638
  for (const [id, entry] of Object.entries(v2Providers)) {
633
639
  if (hasKey(entry)) injectable[id] = entry;
634
640
  }
641
+ // provider_config.json \u8865\u6CE8\u5165\uFF08\u8BFB\u53D6\u5931\u8D25\u9759\u9ED8\u964D\u7EA7\u2014\u2014\u6821\u9A8C\u6E90\u7F3A\u5E2D\u65F6\u5F15\u64CE\u4FA7\u6821\u9A8C\u540C\u6837\u4E0D\u53EF
642
+ // \u7528\uFF0C\u6CE8\u5165\u9762\u7EF4\u6301 v2-only \u73B0\u72B6\uFF1BproviderRules \u7F3A\u5931\u4E0D\u6784\u6210\u51ED\u636E\u9519\u8BEF\uFF09\u3002
643
+ try {
644
+ const pc = JSON.parse(readOrig(PROVIDER_CONFIG_PATH, 'utf8'));
645
+ const pcCfg = pc && typeof pc.config === 'object' && pc.config ? pc.config : {};
646
+ const pcr = typeof pcCfg.providerConfigRules === 'object' && pcCfg.providerConfigRules ? pcCfg.providerConfigRules : {};
647
+ const rules = Array.isArray(pcr.providerRules) ? pcr.providerRules : [];
648
+ const mcr = typeof pcCfg.modelConfigRules === 'object' && pcCfg.modelConfigRules ? pcCfg.modelConfigRules : {};
649
+ const modelRules = Array.isArray(mcr.providerModelRules) ? mcr.providerModelRules : [];
650
+ const modelMeta = {};
651
+ for (const mr of modelRules) {
652
+ if (!mr || typeof mr !== 'object' || typeof mr.providerId !== 'string' || typeof mr.modelId !== 'string') continue;
653
+ (modelMeta[mr.providerId] = modelMeta[mr.providerId] || []).push(mr);
654
+ }
655
+ for (const rule of rules) {
656
+ if (!rule || typeof rule !== 'object') continue;
657
+ const id = typeof rule.providerId === 'string' ? rule.providerId : '';
658
+ const cfg = rule.config && typeof rule.config === 'object' ? rule.config : {};
659
+ const access = cfg.access && typeof cfg.access === 'object' ? cfg.access : {};
660
+ const api = cfg.api && typeof cfg.api === 'object' ? cfg.api : {};
661
+ // v2/real \u5DF2\u6709 \u2192 \u4E0D\u91CD\u590D\u5408\u6210\uFF08v2 \u6761\u76EE\u66F4\u5168\uFF0C\u6574\u6761\u4F18\u5148\u8BED\u4E49\u4E0D\u53D7\u5F71\u54CD\uFF09
662
+ if (!id || injectable[id] || realProviders[id]) continue;
663
+ // hasKey \u7EAA\u5F8B\u540C\u6B3E\uFF1A\u65E0 apiKey \u4E0D\u5408\u6210\uFF1B\u65E0 baseUrl\uFF08endpoint \u7531\u6A21\u677F\u63D0\u4F9B\u7684\u5F62\u6001\uFF09
664
+ // \u4E0D\u5408\u6210\u2014\u2014\u6B8B\u7F3A\u6761\u76EE\u6BD4\u4E0D\u6CE8\u5165\u66F4\u7CDF\uFF0C\u539F\u751F\u300C\u4E0D\u5B58\u5728 Model\u300D\u62A5\u9519\u7167\u65E7\u900F\u51FA
665
+ if (typeof access.apiKey !== 'string' || access.apiKey === '') continue;
666
+ if (typeof api.baseUrl !== 'string' || api.baseUrl === '') continue;
667
+ const order = Array.isArray(cfg.modelOrder) ? cfg.modelOrder
668
+ : (Array.isArray(cfg.personalModelIds) ? cfg.personalModelIds : []);
669
+ const models = {};
670
+ for (const mr of modelMeta[id] || []) {
671
+ const mrCfg = mr.config && typeof mr.config === 'object' ? mr.config : {};
672
+ if (mrCfg.enabled === false) continue; // \u7981\u7528\u6A21\u578B\u4E0D\u8FDB\u6CE8\u518C\u8868\uFF08GUI \u8BED\u4E49\u4E00\u81F4\uFF09
673
+ const props = mrCfg.properties && typeof mrCfg.properties === 'object' ? mrCfg.properties : {};
674
+ models[mr.modelId] = typeof props.contextWindow === 'number'
675
+ ? { limit: { context: props.contextWindow } }
676
+ : {};
677
+ }
678
+ for (const mid of order) {
679
+ if (typeof mid === 'string' && mid !== '' && !(mid in models)) models[mid] = {};
680
+ }
681
+ injectable[id] = {
682
+ name: typeof rule.providerName === 'string' ? rule.providerName : id,
683
+ // provider_config.json \u4E0D\u643A\u5E26\u534F\u8BAE\u5F62\u6001\u2014\u2014standard-personal \u7EC4\u4EE5 openai-compatible
684
+ // \u4E3A\u591A\u6570\u5148\u4F8B\uFF1B\u9519\u914D\u65F6\u8BF7\u6C42\u671F\u534F\u8BAE\u9519\u8BEF\u53EF\u89C1\uFF08\u4E0D\u963B\u585E\u6CE8\u518C\u8868\u88C5\u8F7D\uFF09\uFF0C\u771F\u673A\u6F02\u79FB\u4FE1\u53F7\u660E\u786E
685
+ kind: 'openai-compatible',
686
+ options: { apiKey: access.apiKey, baseURL: api.baseUrl },
687
+ source: 'custom',
688
+ models: models,
689
+ };
690
+ }
691
+ } catch { /* provider_config \u7F3A\u5931/\u635F\u574F \u2192 \u8865\u6CE8\u5165\u9762\u9759\u9ED8\u964D\u7EA7\uFF08v2 \u6CE8\u5165\u4E0D\u53D7\u5F71\u54CD\uFF09 */ }
635
692
  if (Object.keys(injectable).length === 0) return null;
636
693
  const merged = { ...real };
637
- merged.provider = { ...(real.provider && typeof real.provider === 'object' ? real.provider : {}), ...injectable };
694
+ merged.provider = { ...realProviders, ...injectable };
638
695
  if ((!merged.model || typeof merged.model !== 'object' || !merged.model.main)
639
696
  && v2.model && typeof v2.model === 'object' && v2.model.main) {
640
697
  merged.model = { ...(merged.model || {}), main: v2.model.main };
@@ -1973,7 +2030,10 @@ var ZcodeEngine = class {
1973
2030
  // --mode build/edit/plan/yolo 原生权限档位
1974
2031
  permissionMode: "native",
1975
2032
  // [D3-④] 无 turn_end 语义,轮数上限不可兑现(预检 gate 据此同步拒绝)
1976
- maxTurns: false
2033
+ maxTurns: false,
2034
+ // [subagent-model-switch] zcode 引擎不在模型切换设计范围(协议面引擎中立预留,
2035
+ // 后续另立项接入)——setModel 通路未接通,unsupported 如实声明
2036
+ setModel: "unsupported"
1977
2037
  };
1978
2038
  }
1979
2039
  /** 探针(D7):二进制存在 + 版本解析(zcode 无公开契约,版本漂移的入口信号)。 */
@@ -2290,6 +2350,7 @@ var ZcodeEngine = class {
2290
2350
  const env = buildAppServerEnv(this.deps.processEnv ?? process.env);
2291
2351
  env.ZCODE_ENG_CLI_PATH = cliPath;
2292
2352
  env.ZCODE_ENG_V2_CONFIG = this.deps.sources?.v2ConfigPath ?? defaultV2ConfigPath();
2353
+ env.ZCODE_ENG_PROVIDER_CONFIG = this.deps.sources?.personalProviderConfigPath ?? defaultPersonalProviderConfigPath();
2293
2354
  const sessionDbPath = zcodeSessionDbPath(engineDataDir);
2294
2355
  env.ZCODE_SESSION_DB_PATH = sessionDbPath;
2295
2356
  delete env.ZCODE_SESSION_DB;
package/dist/index.cjs CHANGED
@@ -390,6 +390,7 @@ const os = require('node:os');
390
390
 
391
391
  const CLI_PATH = process.env.ZCODE_ENG_CLI_PATH;
392
392
  const V2_PATH = process.env.ZCODE_ENG_V2_CONFIG || path.join(os.homedir(), '.zcode', 'v2', 'config.json');
393
+ const PROVIDER_CONFIG_PATH = process.env.ZCODE_ENG_PROVIDER_CONFIG || path.join(os.homedir(), '.zcode', 'v2', 'provider_config.json');
393
394
  const CONFIG_PATH = path.join(os.homedir(), '.zcode', 'cli', 'config.json');
394
395
 
395
396
  // \u5408\u5E76\u5F62\u6001\uFF1A\u771F\u5B9E cli config \u539F\u6837\uFF08model/plugins/mcp/subagents \u7B49 worker \u7EE7\u627F\u9762\u4E0D\u53D8\uFF09
@@ -398,6 +399,10 @@ const CONFIG_PATH = path.join(os.homedir(), '.zcode', 'cli', 'config.json');
398
399
  // \u914D\u7F6E\uFF082026-08-25 \u4E8B\u6545\uFF1A\u6B8B\u7559\u65E7 key \u538B\u8FC7\u65B0\u51ED\u636E\u81F4 turn 0 401\uFF09\uFF0C\u6545\u4E0D\u53D6 real \u4F18\u5148\u3002
399
400
  // model.main \u7F3A\u5931\u65F6\u53EA\u4ECE v2 \u900F\u4F20\uFF08v2 \u4E5F\u6CA1\u6709\u5219\u4E0D\u4F2A\u9020\u2014\u2014CLI \u7F3A\u7701\u89E3\u6790\u81EA\u4F1A\u843D\u5230\u6CE8\u518C\u8868
400
401
  // \u53EF\u7528\u6A21\u578B\uFF1Bplan \u5BB6\u65CF id \u5DF2\u4E0D\u53EF\u7528\uFF0C\u4E0D\u518D\u515C\u5E95\u4F2A\u9020\uFF09\u3002
402
+ // [D3 \u987A\u5E26\u53D1\u73B0 6] provider_config.json\uFF08\u5F15\u64CE\u4FA7\u6A21\u578B\u6821\u9A8C\u6E90\uFF09\u8865\u6CE8\u5165\uFF1A\u4EC5\u5B58\u5728\u4E8E
403
+ // providerRules \u7684\u4E2A\u4EBA provider\uFF08v2 \u5B57\u5178\u672A\u7269\u5316\uFF09\u4E0D\u5728\u6CE8\u5165\u96C6 \u2192 app-server \u6CE8\u518C\u8868
404
+ // \u7F3A\u6761\u76EE\uFF0C\u663E\u5F0F\u6A21\u578B\u9996\u6D3E\u5373\u62A5\u300CProvider Registry \u4E2D\u4E0D\u5B58\u5728 Model\u300D\u3002\u4E3A\u5E26 apiKey+baseUrl
405
+ // \u4E14 v2/real \u5747\u7F3A\u5931\u7684 rule \u5408\u6210 cli-config \u6761\u76EE\uFF08\u5F62\u72B6\u7167\u6284\u73B0\u7F51\u4E2A\u4EBA\u6761\u76EE\uFF09\u3002
401
406
  // \u8FD4\u56DE null = \u65E0\u53EF\u6CE8\u5165\u51ED\u636E\uFF08v2 \u65E0 provider \u6761\u76EE\uFF09\u2014\u2014\u4E0D patch\uFF0C\u8BA9\u539F\u751F\u62A5\u9519\u900F\u51FA\u3002
402
407
  // \u8BFB\u6E90\u7ECF readOrig \u95F4\u63A5\u53D6\uFF1Apatch \u524D\u9996\u8C03 = fs.readFileSync \u672C\u4F53\uFF1Bpatch \u540E = \u539F\u51FD\u6570
403
408
  // \uFF08\u9632 patch \u540E\u7684\u9012\u5F52\u81EA\u8C03\u7528\uFF09\u3002
@@ -415,6 +420,7 @@ function injectedConfigText() {
415
420
  }
416
421
  return null;
417
422
  }
423
+ const realProviders = real.provider && typeof real.provider === 'object' ? real.provider : {};
418
424
  const v2Providers = v2.provider && typeof v2.provider === 'object' ? v2.provider : {};
419
425
  const hasKey = (entry) => entry && typeof entry === 'object'
420
426
  && entry.options && typeof entry.options.apiKey === 'string' && entry.options.apiKey !== '';
@@ -422,9 +428,60 @@ function injectedConfigText() {
422
428
  for (const [id, entry] of Object.entries(v2Providers)) {
423
429
  if (hasKey(entry)) injectable[id] = entry;
424
430
  }
431
+ // provider_config.json \u8865\u6CE8\u5165\uFF08\u8BFB\u53D6\u5931\u8D25\u9759\u9ED8\u964D\u7EA7\u2014\u2014\u6821\u9A8C\u6E90\u7F3A\u5E2D\u65F6\u5F15\u64CE\u4FA7\u6821\u9A8C\u540C\u6837\u4E0D\u53EF
432
+ // \u7528\uFF0C\u6CE8\u5165\u9762\u7EF4\u6301 v2-only \u73B0\u72B6\uFF1BproviderRules \u7F3A\u5931\u4E0D\u6784\u6210\u51ED\u636E\u9519\u8BEF\uFF09\u3002
433
+ try {
434
+ const pc = JSON.parse(readOrig(PROVIDER_CONFIG_PATH, 'utf8'));
435
+ const pcCfg = pc && typeof pc.config === 'object' && pc.config ? pc.config : {};
436
+ const pcr = typeof pcCfg.providerConfigRules === 'object' && pcCfg.providerConfigRules ? pcCfg.providerConfigRules : {};
437
+ const rules = Array.isArray(pcr.providerRules) ? pcr.providerRules : [];
438
+ const mcr = typeof pcCfg.modelConfigRules === 'object' && pcCfg.modelConfigRules ? pcCfg.modelConfigRules : {};
439
+ const modelRules = Array.isArray(mcr.providerModelRules) ? mcr.providerModelRules : [];
440
+ const modelMeta = {};
441
+ for (const mr of modelRules) {
442
+ if (!mr || typeof mr !== 'object' || typeof mr.providerId !== 'string' || typeof mr.modelId !== 'string') continue;
443
+ (modelMeta[mr.providerId] = modelMeta[mr.providerId] || []).push(mr);
444
+ }
445
+ for (const rule of rules) {
446
+ if (!rule || typeof rule !== 'object') continue;
447
+ const id = typeof rule.providerId === 'string' ? rule.providerId : '';
448
+ const cfg = rule.config && typeof rule.config === 'object' ? rule.config : {};
449
+ const access = cfg.access && typeof cfg.access === 'object' ? cfg.access : {};
450
+ const api = cfg.api && typeof cfg.api === 'object' ? cfg.api : {};
451
+ // v2/real \u5DF2\u6709 \u2192 \u4E0D\u91CD\u590D\u5408\u6210\uFF08v2 \u6761\u76EE\u66F4\u5168\uFF0C\u6574\u6761\u4F18\u5148\u8BED\u4E49\u4E0D\u53D7\u5F71\u54CD\uFF09
452
+ if (!id || injectable[id] || realProviders[id]) continue;
453
+ // hasKey \u7EAA\u5F8B\u540C\u6B3E\uFF1A\u65E0 apiKey \u4E0D\u5408\u6210\uFF1B\u65E0 baseUrl\uFF08endpoint \u7531\u6A21\u677F\u63D0\u4F9B\u7684\u5F62\u6001\uFF09
454
+ // \u4E0D\u5408\u6210\u2014\u2014\u6B8B\u7F3A\u6761\u76EE\u6BD4\u4E0D\u6CE8\u5165\u66F4\u7CDF\uFF0C\u539F\u751F\u300C\u4E0D\u5B58\u5728 Model\u300D\u62A5\u9519\u7167\u65E7\u900F\u51FA
455
+ if (typeof access.apiKey !== 'string' || access.apiKey === '') continue;
456
+ if (typeof api.baseUrl !== 'string' || api.baseUrl === '') continue;
457
+ const order = Array.isArray(cfg.modelOrder) ? cfg.modelOrder
458
+ : (Array.isArray(cfg.personalModelIds) ? cfg.personalModelIds : []);
459
+ const models = {};
460
+ for (const mr of modelMeta[id] || []) {
461
+ const mrCfg = mr.config && typeof mr.config === 'object' ? mr.config : {};
462
+ if (mrCfg.enabled === false) continue; // \u7981\u7528\u6A21\u578B\u4E0D\u8FDB\u6CE8\u518C\u8868\uFF08GUI \u8BED\u4E49\u4E00\u81F4\uFF09
463
+ const props = mrCfg.properties && typeof mrCfg.properties === 'object' ? mrCfg.properties : {};
464
+ models[mr.modelId] = typeof props.contextWindow === 'number'
465
+ ? { limit: { context: props.contextWindow } }
466
+ : {};
467
+ }
468
+ for (const mid of order) {
469
+ if (typeof mid === 'string' && mid !== '' && !(mid in models)) models[mid] = {};
470
+ }
471
+ injectable[id] = {
472
+ name: typeof rule.providerName === 'string' ? rule.providerName : id,
473
+ // provider_config.json \u4E0D\u643A\u5E26\u534F\u8BAE\u5F62\u6001\u2014\u2014standard-personal \u7EC4\u4EE5 openai-compatible
474
+ // \u4E3A\u591A\u6570\u5148\u4F8B\uFF1B\u9519\u914D\u65F6\u8BF7\u6C42\u671F\u534F\u8BAE\u9519\u8BEF\u53EF\u89C1\uFF08\u4E0D\u963B\u585E\u6CE8\u518C\u8868\u88C5\u8F7D\uFF09\uFF0C\u771F\u673A\u6F02\u79FB\u4FE1\u53F7\u660E\u786E
475
+ kind: 'openai-compatible',
476
+ options: { apiKey: access.apiKey, baseURL: api.baseUrl },
477
+ source: 'custom',
478
+ models: models,
479
+ };
480
+ }
481
+ } catch { /* provider_config \u7F3A\u5931/\u635F\u574F \u2192 \u8865\u6CE8\u5165\u9762\u9759\u9ED8\u964D\u7EA7\uFF08v2 \u6CE8\u5165\u4E0D\u53D7\u5F71\u54CD\uFF09 */ }
425
482
  if (Object.keys(injectable).length === 0) return null;
426
483
  const merged = { ...real };
427
- merged.provider = { ...(real.provider && typeof real.provider === 'object' ? real.provider : {}), ...injectable };
484
+ merged.provider = { ...realProviders, ...injectable };
428
485
  if ((!merged.model || typeof merged.model !== 'object' || !merged.model.main)
429
486
  && v2.model && typeof v2.model === 'object' && v2.model.main) {
430
487
  merged.model = { ...(merged.model || {}), main: v2.model.main };
@@ -1991,7 +2048,10 @@ var ZcodeEngine = class {
1991
2048
  // --mode build/edit/plan/yolo 原生权限档位
1992
2049
  permissionMode: "native",
1993
2050
  // [D3-④] 无 turn_end 语义,轮数上限不可兑现(预检 gate 据此同步拒绝)
1994
- maxTurns: false
2051
+ maxTurns: false,
2052
+ // [subagent-model-switch] zcode 引擎不在模型切换设计范围(协议面引擎中立预留,
2053
+ // 后续另立项接入)——setModel 通路未接通,unsupported 如实声明
2054
+ setModel: "unsupported"
1995
2055
  };
1996
2056
  }
1997
2057
  /** 探针(D7):二进制存在 + 版本解析(zcode 无公开契约,版本漂移的入口信号)。 */
@@ -2308,6 +2368,7 @@ var ZcodeEngine = class {
2308
2368
  const env = buildAppServerEnv(this.deps.processEnv ?? process.env);
2309
2369
  env.ZCODE_ENG_CLI_PATH = cliPath;
2310
2370
  env.ZCODE_ENG_V2_CONFIG = this.deps.sources?.v2ConfigPath ?? defaultV2ConfigPath();
2371
+ env.ZCODE_ENG_PROVIDER_CONFIG = this.deps.sources?.personalProviderConfigPath ?? defaultPersonalProviderConfigPath();
2311
2372
  const sessionDbPath = zcodeSessionDbPath(engineDataDir);
2312
2373
  env.ZCODE_SESSION_DB_PATH = sessionDbPath;
2313
2374
  delete env.ZCODE_SESSION_DB;
package/dist/index.js CHANGED
@@ -10,7 +10,7 @@ import {
10
10
  readZcodeSessionView,
11
11
  zcodeDbPathAllowlist,
12
12
  zcodeSessionDbPath
13
- } from "./chunk-NC4FSPIM.js";
13
+ } from "./chunk-PWNJ5JYZ.js";
14
14
 
15
15
  // src/golden-sample.ts
16
16
  var ZCODE_APPSERVER_GOLDEN = {
package/dist/main.cjs CHANGED
@@ -370,6 +370,7 @@ const os = require('node:os');
370
370
 
371
371
  const CLI_PATH = process.env.ZCODE_ENG_CLI_PATH;
372
372
  const V2_PATH = process.env.ZCODE_ENG_V2_CONFIG || path.join(os.homedir(), '.zcode', 'v2', 'config.json');
373
+ const PROVIDER_CONFIG_PATH = process.env.ZCODE_ENG_PROVIDER_CONFIG || path.join(os.homedir(), '.zcode', 'v2', 'provider_config.json');
373
374
  const CONFIG_PATH = path.join(os.homedir(), '.zcode', 'cli', 'config.json');
374
375
 
375
376
  // \u5408\u5E76\u5F62\u6001\uFF1A\u771F\u5B9E cli config \u539F\u6837\uFF08model/plugins/mcp/subagents \u7B49 worker \u7EE7\u627F\u9762\u4E0D\u53D8\uFF09
@@ -378,6 +379,10 @@ const CONFIG_PATH = path.join(os.homedir(), '.zcode', 'cli', 'config.json');
378
379
  // \u914D\u7F6E\uFF082026-08-25 \u4E8B\u6545\uFF1A\u6B8B\u7559\u65E7 key \u538B\u8FC7\u65B0\u51ED\u636E\u81F4 turn 0 401\uFF09\uFF0C\u6545\u4E0D\u53D6 real \u4F18\u5148\u3002
379
380
  // model.main \u7F3A\u5931\u65F6\u53EA\u4ECE v2 \u900F\u4F20\uFF08v2 \u4E5F\u6CA1\u6709\u5219\u4E0D\u4F2A\u9020\u2014\u2014CLI \u7F3A\u7701\u89E3\u6790\u81EA\u4F1A\u843D\u5230\u6CE8\u518C\u8868
380
381
  // \u53EF\u7528\u6A21\u578B\uFF1Bplan \u5BB6\u65CF id \u5DF2\u4E0D\u53EF\u7528\uFF0C\u4E0D\u518D\u515C\u5E95\u4F2A\u9020\uFF09\u3002
382
+ // [D3 \u987A\u5E26\u53D1\u73B0 6] provider_config.json\uFF08\u5F15\u64CE\u4FA7\u6A21\u578B\u6821\u9A8C\u6E90\uFF09\u8865\u6CE8\u5165\uFF1A\u4EC5\u5B58\u5728\u4E8E
383
+ // providerRules \u7684\u4E2A\u4EBA provider\uFF08v2 \u5B57\u5178\u672A\u7269\u5316\uFF09\u4E0D\u5728\u6CE8\u5165\u96C6 \u2192 app-server \u6CE8\u518C\u8868
384
+ // \u7F3A\u6761\u76EE\uFF0C\u663E\u5F0F\u6A21\u578B\u9996\u6D3E\u5373\u62A5\u300CProvider Registry \u4E2D\u4E0D\u5B58\u5728 Model\u300D\u3002\u4E3A\u5E26 apiKey+baseUrl
385
+ // \u4E14 v2/real \u5747\u7F3A\u5931\u7684 rule \u5408\u6210 cli-config \u6761\u76EE\uFF08\u5F62\u72B6\u7167\u6284\u73B0\u7F51\u4E2A\u4EBA\u6761\u76EE\uFF09\u3002
381
386
  // \u8FD4\u56DE null = \u65E0\u53EF\u6CE8\u5165\u51ED\u636E\uFF08v2 \u65E0 provider \u6761\u76EE\uFF09\u2014\u2014\u4E0D patch\uFF0C\u8BA9\u539F\u751F\u62A5\u9519\u900F\u51FA\u3002
382
387
  // \u8BFB\u6E90\u7ECF readOrig \u95F4\u63A5\u53D6\uFF1Apatch \u524D\u9996\u8C03 = fs.readFileSync \u672C\u4F53\uFF1Bpatch \u540E = \u539F\u51FD\u6570
383
388
  // \uFF08\u9632 patch \u540E\u7684\u9012\u5F52\u81EA\u8C03\u7528\uFF09\u3002
@@ -395,6 +400,7 @@ function injectedConfigText() {
395
400
  }
396
401
  return null;
397
402
  }
403
+ const realProviders = real.provider && typeof real.provider === 'object' ? real.provider : {};
398
404
  const v2Providers = v2.provider && typeof v2.provider === 'object' ? v2.provider : {};
399
405
  const hasKey = (entry) => entry && typeof entry === 'object'
400
406
  && entry.options && typeof entry.options.apiKey === 'string' && entry.options.apiKey !== '';
@@ -402,9 +408,60 @@ function injectedConfigText() {
402
408
  for (const [id, entry] of Object.entries(v2Providers)) {
403
409
  if (hasKey(entry)) injectable[id] = entry;
404
410
  }
411
+ // provider_config.json \u8865\u6CE8\u5165\uFF08\u8BFB\u53D6\u5931\u8D25\u9759\u9ED8\u964D\u7EA7\u2014\u2014\u6821\u9A8C\u6E90\u7F3A\u5E2D\u65F6\u5F15\u64CE\u4FA7\u6821\u9A8C\u540C\u6837\u4E0D\u53EF
412
+ // \u7528\uFF0C\u6CE8\u5165\u9762\u7EF4\u6301 v2-only \u73B0\u72B6\uFF1BproviderRules \u7F3A\u5931\u4E0D\u6784\u6210\u51ED\u636E\u9519\u8BEF\uFF09\u3002
413
+ try {
414
+ const pc = JSON.parse(readOrig(PROVIDER_CONFIG_PATH, 'utf8'));
415
+ const pcCfg = pc && typeof pc.config === 'object' && pc.config ? pc.config : {};
416
+ const pcr = typeof pcCfg.providerConfigRules === 'object' && pcCfg.providerConfigRules ? pcCfg.providerConfigRules : {};
417
+ const rules = Array.isArray(pcr.providerRules) ? pcr.providerRules : [];
418
+ const mcr = typeof pcCfg.modelConfigRules === 'object' && pcCfg.modelConfigRules ? pcCfg.modelConfigRules : {};
419
+ const modelRules = Array.isArray(mcr.providerModelRules) ? mcr.providerModelRules : [];
420
+ const modelMeta = {};
421
+ for (const mr of modelRules) {
422
+ if (!mr || typeof mr !== 'object' || typeof mr.providerId !== 'string' || typeof mr.modelId !== 'string') continue;
423
+ (modelMeta[mr.providerId] = modelMeta[mr.providerId] || []).push(mr);
424
+ }
425
+ for (const rule of rules) {
426
+ if (!rule || typeof rule !== 'object') continue;
427
+ const id = typeof rule.providerId === 'string' ? rule.providerId : '';
428
+ const cfg = rule.config && typeof rule.config === 'object' ? rule.config : {};
429
+ const access = cfg.access && typeof cfg.access === 'object' ? cfg.access : {};
430
+ const api = cfg.api && typeof cfg.api === 'object' ? cfg.api : {};
431
+ // v2/real \u5DF2\u6709 \u2192 \u4E0D\u91CD\u590D\u5408\u6210\uFF08v2 \u6761\u76EE\u66F4\u5168\uFF0C\u6574\u6761\u4F18\u5148\u8BED\u4E49\u4E0D\u53D7\u5F71\u54CD\uFF09
432
+ if (!id || injectable[id] || realProviders[id]) continue;
433
+ // hasKey \u7EAA\u5F8B\u540C\u6B3E\uFF1A\u65E0 apiKey \u4E0D\u5408\u6210\uFF1B\u65E0 baseUrl\uFF08endpoint \u7531\u6A21\u677F\u63D0\u4F9B\u7684\u5F62\u6001\uFF09
434
+ // \u4E0D\u5408\u6210\u2014\u2014\u6B8B\u7F3A\u6761\u76EE\u6BD4\u4E0D\u6CE8\u5165\u66F4\u7CDF\uFF0C\u539F\u751F\u300C\u4E0D\u5B58\u5728 Model\u300D\u62A5\u9519\u7167\u65E7\u900F\u51FA
435
+ if (typeof access.apiKey !== 'string' || access.apiKey === '') continue;
436
+ if (typeof api.baseUrl !== 'string' || api.baseUrl === '') continue;
437
+ const order = Array.isArray(cfg.modelOrder) ? cfg.modelOrder
438
+ : (Array.isArray(cfg.personalModelIds) ? cfg.personalModelIds : []);
439
+ const models = {};
440
+ for (const mr of modelMeta[id] || []) {
441
+ const mrCfg = mr.config && typeof mr.config === 'object' ? mr.config : {};
442
+ if (mrCfg.enabled === false) continue; // \u7981\u7528\u6A21\u578B\u4E0D\u8FDB\u6CE8\u518C\u8868\uFF08GUI \u8BED\u4E49\u4E00\u81F4\uFF09
443
+ const props = mrCfg.properties && typeof mrCfg.properties === 'object' ? mrCfg.properties : {};
444
+ models[mr.modelId] = typeof props.contextWindow === 'number'
445
+ ? { limit: { context: props.contextWindow } }
446
+ : {};
447
+ }
448
+ for (const mid of order) {
449
+ if (typeof mid === 'string' && mid !== '' && !(mid in models)) models[mid] = {};
450
+ }
451
+ injectable[id] = {
452
+ name: typeof rule.providerName === 'string' ? rule.providerName : id,
453
+ // provider_config.json \u4E0D\u643A\u5E26\u534F\u8BAE\u5F62\u6001\u2014\u2014standard-personal \u7EC4\u4EE5 openai-compatible
454
+ // \u4E3A\u591A\u6570\u5148\u4F8B\uFF1B\u9519\u914D\u65F6\u8BF7\u6C42\u671F\u534F\u8BAE\u9519\u8BEF\u53EF\u89C1\uFF08\u4E0D\u963B\u585E\u6CE8\u518C\u8868\u88C5\u8F7D\uFF09\uFF0C\u771F\u673A\u6F02\u79FB\u4FE1\u53F7\u660E\u786E
455
+ kind: 'openai-compatible',
456
+ options: { apiKey: access.apiKey, baseURL: api.baseUrl },
457
+ source: 'custom',
458
+ models: models,
459
+ };
460
+ }
461
+ } catch { /* provider_config \u7F3A\u5931/\u635F\u574F \u2192 \u8865\u6CE8\u5165\u9762\u9759\u9ED8\u964D\u7EA7\uFF08v2 \u6CE8\u5165\u4E0D\u53D7\u5F71\u54CD\uFF09 */ }
405
462
  if (Object.keys(injectable).length === 0) return null;
406
463
  const merged = { ...real };
407
- merged.provider = { ...(real.provider && typeof real.provider === 'object' ? real.provider : {}), ...injectable };
464
+ merged.provider = { ...realProviders, ...injectable };
408
465
  if ((!merged.model || typeof merged.model !== 'object' || !merged.model.main)
409
466
  && v2.model && typeof v2.model === 'object' && v2.model.main) {
410
467
  merged.model = { ...(merged.model || {}), main: v2.model.main };
@@ -1971,7 +2028,10 @@ var ZcodeEngine = class {
1971
2028
  // --mode build/edit/plan/yolo 原生权限档位
1972
2029
  permissionMode: "native",
1973
2030
  // [D3-④] 无 turn_end 语义,轮数上限不可兑现(预检 gate 据此同步拒绝)
1974
- maxTurns: false
2031
+ maxTurns: false,
2032
+ // [subagent-model-switch] zcode 引擎不在模型切换设计范围(协议面引擎中立预留,
2033
+ // 后续另立项接入)——setModel 通路未接通,unsupported 如实声明
2034
+ setModel: "unsupported"
1975
2035
  };
1976
2036
  }
1977
2037
  /** 探针(D7):二进制存在 + 版本解析(zcode 无公开契约,版本漂移的入口信号)。 */
@@ -2288,6 +2348,7 @@ var ZcodeEngine = class {
2288
2348
  const env = buildAppServerEnv(this.deps.processEnv ?? process.env);
2289
2349
  env.ZCODE_ENG_CLI_PATH = cliPath;
2290
2350
  env.ZCODE_ENG_V2_CONFIG = this.deps.sources?.v2ConfigPath ?? defaultV2ConfigPath();
2351
+ env.ZCODE_ENG_PROVIDER_CONFIG = this.deps.sources?.personalProviderConfigPath ?? defaultPersonalProviderConfigPath();
2291
2352
  const sessionDbPath = zcodeSessionDbPath(engineDataDir);
2292
2353
  env.ZCODE_SESSION_DB_PATH = sessionDbPath;
2293
2354
  delete env.ZCODE_SESSION_DB;
package/dist/main.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  EngineProtocolServer
3
- } from "./chunk-NC4FSPIM.js";
3
+ } from "./chunk-PWNJ5JYZ.js";
4
4
 
5
5
  // src/main.ts
6
6
  import {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zhushanwen/zcode-subagent-cli",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "description": "zcode subagent engine as an independent CLI package (W5 of subagent-engine-protocolization): speaks engine-protocol v1 over NDJSON stdio, depends only on @zhushanwen/subagent-engine-sdk (never subagent-core)",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -46,7 +46,8 @@
46
46
  "resume": "cold",
47
47
  "interrupt": "kill-only",
48
48
  "permissionMode": "native",
49
- "maxTurns": false
49
+ "maxTurns": false,
50
+ "setModel": "unsupported"
50
51
  },
51
52
  "modelCatalog": {
52
53
  "dynamic": true,
@@ -62,7 +63,7 @@
62
63
  "dist/"
63
64
  ],
64
65
  "dependencies": {
65
- "@zhushanwen/subagent-engine-sdk": "0.9.0"
66
+ "@zhushanwen/subagent-engine-sdk": "0.10.0"
66
67
  },
67
68
  "devDependencies": {
68
69
  "@types/node": "^24.0.0",