@peterwangze/claude-trigger-router 1.0.2 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -30,8 +30,8 @@ ctr setup
30
30
  `ctr setup` 会:
31
31
 
32
32
  - 优先检查当前配置是否可直接复用
33
- - 检测旧版 `~/.ccr/config.yaml` 并优先提供迁移
34
- - 在需要新建时,先询问默认模型 ID,再收集最少必要接入信息
33
+ - 检测旧版 `~/.ccr/config.yaml` 或 `~/.claude-code-router/config.yaml` 并优先提供迁移
34
+ - 在需要新建时,先确认接入方式与 provider 预设,再带出默认模型和默认模型 ID 供确认
35
35
  - 只生成最小可用配置(`Models + Router.default`),高级路由稍后再补
36
36
  - 保存配置后启动服务并进入 Claude Code
37
37
 
@@ -262,7 +262,7 @@ Models:
262
262
  如果你还在使用旧的 `Providers + provider,model` 配置:
263
263
 
264
264
  - 当前版本仍然兼容旧格式
265
- - `ctr setup` 会优先尝试迁移旧 `ccr` 配置
265
+ - `ctr setup` 会优先尝试迁移旧 `ccr` / `claude-code-router` 配置
266
266
  - 路由字段推荐逐步改成直接引用 `Models[].id`
267
267
 
268
268
  迁移后的核心变化是:
@@ -279,6 +279,8 @@ Models:
279
279
  ```bash
280
280
  ctr setup
281
281
  ctr init
282
+ ctr version
283
+ ctr upgrade
282
284
  ctr start
283
285
  ctr start --daemon
284
286
  ctr stop
package/dist/cli.js CHANGED
@@ -5882,7 +5882,7 @@ function decideSetupBranch(input2) {
5882
5882
  ensureNoLegacyAction(legacyConfigAction);
5883
5883
  return { kind: "reuse_current" };
5884
5884
  }
5885
- if (currentConfigAction === "overwrite") {
5885
+ if (currentConfigAction === "overwrite" || currentConfigAction === "fresh") {
5886
5886
  return ensureLegacyFlow(detection, legacyConfigAction);
5887
5887
  }
5888
5888
  return invalidAction();
@@ -6083,43 +6083,51 @@ function readStructuredConfigFile(filePath) {
6083
6083
  }
6084
6084
  return import_js_yaml.default.load(content);
6085
6085
  }
6086
- async function readCurrentConfig() {
6087
- const candidates = [CONFIG_FILE, CONFIG_FILE_YML, CONFIG_FILE_JSON];
6088
- const currentPath = candidates.find((filePath) => (0, import_fs6.existsSync)(filePath));
6089
- if (!currentPath) {
6086
+ async function readLegacyConfig(deps = {}) {
6087
+ const baseHomeDir = deps.homeDir || (0, import_os3.homedir)();
6088
+ const exists = deps.exists || import_fs6.existsSync;
6089
+ const readConfig = deps.readConfig || readStructuredConfigFile;
6090
+ const overridePath = process.env.CTR_SETUP_LEGACY_CONFIG_PATH;
6091
+ const candidatePaths = overridePath ? [overridePath] : [
6092
+ (0, import_path6.join)(baseHomeDir, ".ccr", "config.yaml"),
6093
+ (0, import_path6.join)(baseHomeDir, ".claude-code-router", "config.yaml")
6094
+ ];
6095
+ const legacyPath = candidatePaths.find((filePath) => exists(filePath));
6096
+ if (!legacyPath) {
6090
6097
  return { kind: "missing" };
6091
6098
  }
6092
6099
  try {
6093
6100
  return {
6094
6101
  kind: "found",
6095
- path: currentPath,
6096
- format: currentPath.endsWith(".json") ? "json" : currentPath.endsWith(".yml") ? "yml" : "yaml",
6097
- config: readStructuredConfigFile(currentPath) ?? {}
6102
+ path: legacyPath,
6103
+ config: readConfig(legacyPath)
6098
6104
  };
6099
6105
  } catch (error) {
6100
6106
  return {
6101
- kind: "parse_error",
6102
- path: currentPath,
6103
- format: currentPath.endsWith(".json") ? "json" : currentPath.endsWith(".yml") ? "yml" : "yaml",
6107
+ kind: "read_error",
6108
+ path: legacyPath,
6104
6109
  error: error instanceof Error ? error.message : String(error)
6105
6110
  };
6106
6111
  }
6107
6112
  }
6108
- async function readLegacyConfig() {
6109
- const legacyPath = process.env.CTR_SETUP_LEGACY_CONFIG_PATH || (0, import_path6.join)((0, import_os3.homedir)(), ".ccr", "config.yaml");
6110
- if (!(0, import_fs6.existsSync)(legacyPath)) {
6113
+ async function readCurrentConfig() {
6114
+ const candidates = [CONFIG_FILE, CONFIG_FILE_YML, CONFIG_FILE_JSON];
6115
+ const currentPath = candidates.find((filePath) => (0, import_fs6.existsSync)(filePath));
6116
+ if (!currentPath) {
6111
6117
  return { kind: "missing" };
6112
6118
  }
6113
6119
  try {
6114
6120
  return {
6115
6121
  kind: "found",
6116
- path: legacyPath,
6117
- config: readStructuredConfigFile(legacyPath)
6122
+ path: currentPath,
6123
+ format: currentPath.endsWith(".json") ? "json" : currentPath.endsWith(".yml") ? "yml" : "yaml",
6124
+ config: readStructuredConfigFile(currentPath) ?? {}
6118
6125
  };
6119
6126
  } catch (error) {
6120
6127
  return {
6121
- kind: "read_error",
6122
- path: legacyPath,
6128
+ kind: "parse_error",
6129
+ path: currentPath,
6130
+ format: currentPath.endsWith(".json") ? "json" : currentPath.endsWith(".yml") ? "yml" : "yaml",
6123
6131
  error: error instanceof Error ? error.message : String(error)
6124
6132
  };
6125
6133
  }
@@ -6161,7 +6169,10 @@ function mapValidCurrentConfigChoice(choice) {
6161
6169
  if (choice === "overwrite" || choice === "\u68C0\u67E5\u5E76\u8C03\u6574\u5F53\u524D\u914D\u7F6E") {
6162
6170
  return "overwrite";
6163
6171
  }
6164
- if (choice === "cancel" || choice === "\u653E\u5F03\u5F53\u524D\u914D\u7F6E\uFF0C\u91CD\u65B0\u5F00\u59CB") {
6172
+ if (choice === "fresh" || choice === "\u653E\u5F03\u5F53\u524D\u914D\u7F6E\uFF0C\u91CD\u65B0\u5F00\u59CB") {
6173
+ return "fresh";
6174
+ }
6175
+ if (choice === "cancel") {
6165
6176
  return "cancel";
6166
6177
  }
6167
6178
  throw new Error("invalid current config action");
@@ -6276,8 +6287,15 @@ function toDraftFromConfig(config) {
6276
6287
  }
6277
6288
  };
6278
6289
  }
6290
+ function toSuggestedModelId(providerName, model, preset) {
6291
+ const presetDefinition = getProviderPreset(preset);
6292
+ if (presetDefinition?.suggested_id) {
6293
+ return presetDefinition.suggested_id;
6294
+ }
6295
+ const source = model || providerName || "model";
6296
+ return source.toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "") || "model";
6297
+ }
6279
6298
  async function buildFreshConfig(io) {
6280
- const modelId = await io.input("\u9ED8\u8BA4\u6A21\u578B ID");
6281
6299
  const connectMode = await io.choose("\u8FD9\u4E2A\u6A21\u578B\u63A5\u5230\u54EA\u91CC\uFF1F", ["\u4F7F\u7528\u5E38\u89C1\u63A5\u5165\u6A21\u677F", "\u624B\u52A8\u586B\u5199\u63A5\u53E3"]);
6282
6300
  let preset = "custom";
6283
6301
  let providerName = "provider";
@@ -6292,7 +6310,9 @@ async function buildFreshConfig(io) {
6292
6310
  apiBaseUrl = await io.input("API Base URL");
6293
6311
  }
6294
6312
  const apiKey = await io.input("API Key");
6295
- const model = await io.input("\u4E0A\u6E38\u6A21\u578B\u540D");
6313
+ const presetDefinition = getProviderPreset(preset);
6314
+ const model = await io.input("\u4E0A\u6E38\u6A21\u578B\u540D", presetDefinition?.default_model ?? "");
6315
+ const modelId = await io.input("\u9ED8\u8BA4\u6A21\u578B ID", toSuggestedModelId(providerName, model, preset));
6296
6316
  const capabilityMode = await io.choose("\u662F\u5426\u914D\u7F6E capability \u63D0\u793A", ["\u4FDD\u6301\u9ED8\u8BA4", "\u914D\u7F6E capability \u63D0\u793A"]);
6297
6317
  const draft = buildMinimalConfig({
6298
6318
  providers: [
@@ -6494,6 +6514,14 @@ __export(cli_exports, {
6494
6514
  runClaudeCode: () => runClaudeCode
6495
6515
  });
6496
6516
  module.exports = __toCommonJS(cli_exports);
6517
+ function getPackageInfo() {
6518
+ const content = (0, import_fs7.readFileSync)(PACKAGE_JSON_PATH, "utf-8");
6519
+ const pkg = JSON.parse(content);
6520
+ return {
6521
+ name: pkg.name ?? "@peterwangze/claude-trigger-router",
6522
+ version: pkg.version ?? "unknown"
6523
+ };
6524
+ }
6497
6525
  function getArgs() {
6498
6526
  return process.argv.slice(2);
6499
6527
  }
@@ -6549,6 +6577,8 @@ Claude Trigger Router - \u667A\u80FD\u89E6\u53D1\u8DEF\u7531\u5668
6549
6577
  stop \u505C\u6B62\u540E\u53F0\u670D\u52A1
6550
6578
  restart \u91CD\u542F\u540E\u53F0\u670D\u52A1
6551
6579
  status \u67E5\u770B\u670D\u52A1\u8FD0\u884C\u72B6\u6001\uFF08PID\u3001\u7AEF\u53E3\u3001\u542F\u52A8\u65F6\u95F4\uFF09
6580
+ version \u67E5\u770B\u5F53\u524D\u5B89\u88C5\u7248\u672C\u4E0E\u5305\u4FE1\u606F
6581
+ upgrade \u67E5\u770B\u5347\u7EA7\u5230\u6700\u65B0 npm \u7248\u672C\u7684\u6307\u5F15
6552
6582
  code \u901A\u8FC7\u8DEF\u7531\u5668\u8FD0\u884C Claude Code\uFF08\u9700\u5148\u542F\u52A8\u670D\u52A1\uFF09
6553
6583
  ui \u6253\u5F00\u7BA1\u7406 API \u8BF4\u660E\u9875\uFF08Web UI \u5F00\u53D1\u4E2D\uFF09
6554
6584
  help \u663E\u793A\u6B64\u5E2E\u52A9\u4FE1\u606F
@@ -6561,6 +6591,8 @@ Claude Trigger Router - \u667A\u80FD\u89E6\u53D1\u8DEF\u7531\u5668
6561
6591
  \u4F7F\u7528\u793A\u4F8B\uFF1A
6562
6592
  ctr setup # \u590D\u7528\u5F53\u524D\u914D\u7F6E / \u8FC1\u79FB\u65E7\u914D\u7F6E / \u65B0\u5EFA\u6700\u5C0F\u914D\u7F6E
6563
6593
  ctr init # \u521D\u59CB\u5316\u6700\u5C0F\u914D\u7F6E\u6A21\u677F
6594
+ ctr version # \u67E5\u770B\u5F53\u524D\u5B89\u88C5\u7248\u672C
6595
+ ctr upgrade # \u67E5\u770B\u5347\u7EA7\u5230\u6700\u65B0\u7248\u672C\u7684\u547D\u4EE4
6564
6596
  ctr start # \u524D\u53F0\u542F\u52A8\uFF08\u63A8\u8350\u9996\u6B21\u4F7F\u7528\uFF0C\u4FBF\u4E8E\u67E5\u770B\u65E5\u5FD7\uFF09
6565
6597
  ctr start --daemon # \u540E\u53F0\u542F\u52A8
6566
6598
  ctr status # \u67E5\u770B\u670D\u52A1\u72B6\u6001
@@ -6577,6 +6609,58 @@ Claude Trigger Router - \u667A\u80FD\u89E6\u53D1\u8DEF\u7531\u5668
6577
6609
  \u66F4\u591A\u4FE1\u606F\uFF1Ahttps://github.com/peterwangze/claude-trigger-router
6578
6610
  `);
6579
6611
  }
6612
+ async function getLatestPackageVersion(timeoutMs = 1500) {
6613
+ try {
6614
+ const response = await fetch(PACKAGE_REGISTRY_LATEST_URL, {
6615
+ signal: AbortSignal.timeout(timeoutMs)
6616
+ });
6617
+ if (!response.ok) {
6618
+ return null;
6619
+ }
6620
+ const payload = await response.json();
6621
+ return typeof payload.version === "string" ? payload.version : null;
6622
+ } catch {
6623
+ return null;
6624
+ }
6625
+ }
6626
+ function isNewerVersion(current, latest) {
6627
+ const currentParts = current.split(".").map((part) => Number.parseInt(part, 10));
6628
+ const latestParts = latest.split(".").map((part) => Number.parseInt(part, 10));
6629
+ const length = Math.max(currentParts.length, latestParts.length);
6630
+ for (let index = 0; index < length; index += 1) {
6631
+ const currentValue = Number.isFinite(currentParts[index]) ? currentParts[index] : 0;
6632
+ const latestValue = Number.isFinite(latestParts[index]) ? latestParts[index] : 0;
6633
+ if (latestValue > currentValue) {
6634
+ return true;
6635
+ }
6636
+ if (latestValue < currentValue) {
6637
+ return false;
6638
+ }
6639
+ }
6640
+ return false;
6641
+ }
6642
+ async function printVersion() {
6643
+ const pkg = getPackageInfo();
6644
+ const latestVersion = await getLatestPackageVersion();
6645
+ console.log(`Package: ${pkg.name}`);
6646
+ console.log(`Version: ${pkg.version}`);
6647
+ console.log(`Latest: ${latestVersion ?? "unavailable"}`);
6648
+ if (latestVersion && isNewerVersion(pkg.version, latestVersion)) {
6649
+ console.log(`Upgrade: npm install -g ${pkg.name}@latest`);
6650
+ }
6651
+ console.log(`NPM: ${PACKAGE_PAGE_URL}`);
6652
+ }
6653
+ function printUpgradeGuidance() {
6654
+ const pkg = getPackageInfo();
6655
+ console.log(`\u5F53\u524D\u5B89\u88C5\u7248\u672C\uFF1A${pkg.version}`);
6656
+ console.log(`\u5305\u540D\uFF1A${pkg.name}`);
6657
+ console.log("\u5347\u7EA7\u5230\u6700\u65B0\u7248\u672C\uFF1A");
6658
+ console.log(` npm install -g ${pkg.name}@latest`);
6659
+ console.log("\u8BF7\u5728\u5F53\u524D ctr \u8FDB\u7A0B\u5916\u6267\u884C\u5347\u7EA7\u547D\u4EE4\uFF0C\u907F\u514D\u81EA\u5347\u7EA7\u65F6\u5360\u7528\u5F53\u524D\u6587\u4EF6\u3002");
6660
+ console.log("\u5982\u679C\u4F60\u6700\u521D\u662F\u901A\u8FC7 GitHub \u6E90\u5B89\u88C5\uFF0C\u8BF7\u7EE7\u7EED\u4F7F\u7528\u539F\u5B89\u88C5\u6765\u6E90\uFF0C\u5F53\u524D\u547D\u4EE4\u4E0D\u4F1A\u81EA\u52A8\u5207\u6362\u6765\u6E90\u3002");
6661
+ console.log("\u5168\u5C40\u5B89\u88C5\u5728\u67D0\u4E9B\u73AF\u5883\u4E0B\u53EF\u80FD\u9700\u8981\u7BA1\u7406\u5458/root \u6743\u9650\u3002");
6662
+ console.log(`NPM: ${PACKAGE_PAGE_URL}`);
6663
+ }
6580
6664
  function initConfig2() {
6581
6665
  const force = hasArg("--force");
6582
6666
  const existingConfig = [CONFIG_FILE, CONFIG_FILE_YML, CONFIG_FILE_JSON].find(import_fs7.existsSync);
@@ -6763,6 +6847,12 @@ async function main() {
6763
6847
  case "status":
6764
6848
  showStatus();
6765
6849
  break;
6850
+ case "version":
6851
+ await printVersion();
6852
+ break;
6853
+ case "upgrade":
6854
+ printUpgradeGuidance();
6855
+ break;
6766
6856
  case "restart":
6767
6857
  restartService();
6768
6858
  break;
@@ -6785,7 +6875,7 @@ async function main() {
6785
6875
  process.exit(command ? 1 : 0);
6786
6876
  }
6787
6877
  }
6788
- var import_child_process2, import_path7, import_openurl, import_fs7;
6878
+ var import_child_process2, import_path7, import_openurl, import_fs7, PACKAGE_JSON_PATH, PACKAGE_PAGE_URL, PACKAGE_REGISTRY_LATEST_URL;
6789
6879
  var init_cli = __esm({
6790
6880
  "src/cli.ts"() {
6791
6881
  import_child_process2 = require("child_process");
@@ -6797,6 +6887,9 @@ var init_cli = __esm({
6797
6887
  init_constants();
6798
6888
  init_service_health();
6799
6889
  init_setup2();
6890
+ PACKAGE_JSON_PATH = (0, import_path7.join)(__dirname, "..", "package.json");
6891
+ PACKAGE_PAGE_URL = "https://www.npmjs.com/package/@peterwangze/claude-trigger-router";
6892
+ PACKAGE_REGISTRY_LATEST_URL = "https://registry.npmjs.org/@peterwangze%2Fclaude-trigger-router/latest";
6800
6893
  if (process.env.CTR_SKIP_MAIN !== "1") {
6801
6894
  main().catch((error) => {
6802
6895
  console.error("Error:", error);