ai-git-tools 2.0.81 → 2.1.1

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
@@ -238,7 +238,7 @@ npx ai-git-tools model-info [選項]
238
238
 
239
239
  \`\`\`bash
240
240
  npx ai-git-tools model-info
241
- npx ai-git-tools model-info --model gpt-4.1
241
+ npx ai-git-tools model-info --model claude-haiku-4.5
242
242
  npx ai-git-tools model-info --filter claude
243
243
  npx ai-git-tools model-info --json
244
244
  \`\`\`
@@ -253,7 +253,7 @@ npx ai-git-tools model-info --json
253
253
  export default {
254
254
  // AI 設定
255
255
  ai: {
256
- model: 'gpt-4.1', // AI 模型
256
+ model: 'claude-haiku-4.5', // AI 模型
257
257
  maxDiffLength: 8000, // 最大 diff 長度
258
258
  maxRetries: 3, // 失敗重試次數
259
259
  },
@@ -449,7 +449,7 @@ A: 需要。本工具使用 GitHub Copilot SDK,需要有 GitHub Copilot 訂閱
449
449
 
450
450
  ### Q: 可以使用其他 AI 模型嗎?
451
451
 
452
- A: 可以。支援 GPT-4.1、Claude Haiku 4.5、Claude Sonnet 4.5 等模型,可在配置檔中設定。
452
+ A: 可以。支援Claude Haiku 4.5、Claude Sonnet 4.5 等模型,可在配置檔中設定。
453
453
 
454
454
  ### Q: 配置檔一定要放在專案根目錄嗎?
455
455
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-git-tools",
3
- "version": "2.0.81",
3
+ "version": "2.1.1",
4
4
  "description": "AI-powered Git automation tools for commit messages and PR generation",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
@@ -8,7 +8,7 @@
8
8
  "ai-git-tools": "./bin/cli.js"
9
9
  },
10
10
  "scripts": {
11
- "test": "echo \"Error: no test specified\" && exit 1",
11
+ "test": "node --test test/*.test.js",
12
12
  "prepare": "chmod +x bin/cli.js",
13
13
  "lint": "eslint src/**/*.js",
14
14
  "format": "prettier --write \"src/**/*.js\" \"bin/**/*.js\"",
@@ -39,11 +39,11 @@
39
39
  "CHANGELOG.md"
40
40
  ],
41
41
  "dependencies": {
42
- "@github/copilot-sdk": "^0.2.1",
43
- "commander": "^12.0.0",
42
+ "@github/copilot-sdk": "^1.0.11",
44
43
  "chalk": "^5.3.0",
45
- "ora": "^8.0.1",
46
- "inquirer": "^9.2.0"
44
+ "commander": "^12.0.0",
45
+ "inquirer": "^9.2.0",
46
+ "ora": "^8.0.1"
47
47
  },
48
48
  "devDependencies": {
49
49
  "eslint": "^8.57.0",
@@ -16,7 +16,7 @@ const DEFAULT_CONFIG = `/**
16
16
  export default {
17
17
  // AI 相關配置
18
18
  ai: {
19
- model: 'gpt-4.1', // AI 模型
19
+ model: 'claude-haiku-4.5', // AI 模型
20
20
  maxDiffLength: 8000, // 最大 diff 長度
21
21
  maxRetries: 3, // 最大重試次數
22
22
  },
@@ -12,6 +12,7 @@ import {
12
12
  filterModels,
13
13
  formatPrice,
14
14
  formatTokenCount,
15
+ getTokenPrices,
15
16
  } from '../data/copilot-models.js';
16
17
 
17
18
  const logger = new Logger();
@@ -38,6 +39,10 @@ function formatCapabilities(supports = {}) {
38
39
  if (supports.reasoningEffort || supports.reasoning_effort) caps.push('reasoning');
39
40
  if (supports.streaming) caps.push('streaming');
40
41
  if (supports.parallel_tool_calls) caps.push('parallel-tools');
42
+ if (supports.structured_outputs) caps.push('structured-output');
43
+ if (supports.adaptive_thinking && supports.adaptive_thinking !== 'unsupported') {
44
+ caps.push('adaptive-thinking');
45
+ }
41
46
  return caps.length > 0 ? caps.join('、') : '—';
42
47
  }
43
48
 
@@ -64,33 +69,49 @@ function policyStateLabel(state) {
64
69
  * @param {object} model
65
70
  */
66
71
  function printModel(model) {
67
- const billing = model.billing?.token_prices;
72
+ const billing = model.tokenPrices || getTokenPrices(model.billing);
73
+ const capabilities = model.capabilities || {};
68
74
 
69
75
  console.log(`\n ${logger.colors?.cyan ?? ''}${model.id}${logger.colors?.reset ?? ''}`);
70
76
  console.log(' ─────────────────────────────────────────────────────────────');
71
77
  console.log(` 名稱: ${model.name}`);
72
78
  console.log(` 供應商: ${model.provider}`);
79
+ console.log(` 模型家族: ${capabilities.family || '—'}`);
80
+ console.log(` 模型類型: ${capabilities.type || '—'}`);
81
+ console.log(` Tokenizer: ${capabilities.tokenizer || '—'}`);
82
+ console.log(` 模型分類: ${model.modelPickerCategory || '—'}`);
83
+ console.log(` 價格分類: ${model.modelPickerPriceCategory || '—'}`);
73
84
  console.log(` 描述: ${model.description}`);
74
85
  console.log(` 上下文: ${model.contextWindow}`);
75
86
  console.log(` 最大輸出: ${model.maxOutputTokens}`);
76
87
  console.log(` 建議用途: ${formatRecommendedFor(model.recommendedFor)}`);
77
88
  console.log(` 速度: ${model.speed}`);
78
89
  console.log(` 狀態: ${policyStateLabel(model.policy?.state)}`);
79
- console.log(` 能力: ${formatCapabilities(model.capabilities?.supports)}`);
90
+ console.log(` 能力: ${formatCapabilities(capabilities.supports)}`);
80
91
  if (billing && billing.batch_size > 0) {
81
92
  const hasAnyPrice =
82
93
  billing.input_price > 0 || billing.output_price > 0 || billing.cache_price > 0;
83
94
  if (hasAnyPrice) {
84
95
  console.log(` 價格(預估):`);
85
96
  console.log(
86
- ` 輸入: ${formatPrice(billing.input_price, billing.batch_size)} / ${formatTokenCount(billing.batch_size)} tokens`
97
+ ` 輸入: ${formatPrice(billing.input_price, billing.batch_size, billing.price_scale)} / ${formatTokenCount(billing.batch_size)} tokens`
87
98
  );
88
99
  console.log(
89
- ` 輸出: ${formatPrice(billing.output_price, billing.batch_size)} / ${formatTokenCount(billing.batch_size)} tokens`
100
+ ` 輸出: ${formatPrice(billing.output_price, billing.batch_size, billing.price_scale)} / ${formatTokenCount(billing.batch_size)} tokens`
90
101
  );
91
102
  if (billing.cache_price !== undefined) {
92
103
  console.log(
93
- ` 快取: ${formatPrice(billing.cache_price, billing.batch_size)} / ${formatTokenCount(billing.batch_size)} tokens`
104
+ ` 快取: ${formatPrice(billing.cache_price, billing.batch_size, billing.price_scale)} / ${formatTokenCount(billing.batch_size)} tokens`
105
+ );
106
+ }
107
+ if (billing.cache_read_price !== undefined) {
108
+ console.log(
109
+ ` 快取讀取: ${formatPrice(billing.cache_read_price, billing.batch_size, billing.price_scale)} / ${formatTokenCount(billing.batch_size)} tokens`
110
+ );
111
+ }
112
+ if (billing.cache_write_price !== undefined) {
113
+ console.log(
114
+ ` 快取寫入: ${formatPrice(billing.cache_write_price, billing.batch_size, billing.price_scale)} / ${formatTokenCount(billing.batch_size)} tokens`
94
115
  );
95
116
  }
96
117
  }
@@ -29,7 +29,7 @@ export class AIClient {
29
29
  /**
30
30
  * 發送 prompt 並等待回應(帶重試機制和超時保護)
31
31
  */
32
- static async sendAndWait(prompt, model = 'gpt-4.1', maxRetries = 3, timeout = 150000) {
32
+ static async sendAndWait(prompt, model = 'claude-haiku-4.5', maxRetries = 3, timeout = 150000) {
33
33
  let lastError = null;
34
34
 
35
35
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
@@ -12,7 +12,7 @@ import { resolve } from 'path';
12
12
  */
13
13
  const DEFAULT_CONFIG = {
14
14
  ai: {
15
- model: 'gpt-4.1',
15
+ model: 'claude-haiku-4.5',
16
16
  maxDiffLength: 8000,
17
17
  maxRetries: 3,
18
18
  },
@@ -193,7 +193,7 @@ function showHelp() {
193
193
 
194
194
  選項:
195
195
  --base <branch> 指定目標分支 (預設: 使用配置檔的 defaultBase 或自動偵測)
196
- --model <model> 指定 AI 模型 (預設: gpt-4.1)
196
+ --model <model> 指定 AI 模型 (預設: claude-haiku-4.5)
197
197
  --preview 僅預覽 PR 內容,不實際創建
198
198
  --no-confirm 跳過確認直接創建
199
199
  --auto-labels 自動添加 Labels (預設啟用)
@@ -13,6 +13,7 @@ const MODEL_ENHANCEMENTS = {};
13
13
  export function inferProvider(modelId) {
14
14
  if (modelId.startsWith('claude')) return 'Anthropic';
15
15
  if (modelId.startsWith('gpt')) return 'OpenAI';
16
+ if (modelId.startsWith('gemini')) return 'Google';
16
17
  return 'Unknown';
17
18
  }
18
19
 
@@ -44,6 +45,30 @@ export function getModelEnhancement(modelId) {
44
45
  );
45
46
  }
46
47
 
48
+ /**
49
+ * 正規化 Copilot SDK 的價格欄位
50
+ * @param {object} billing
51
+ * @returns {object | null}
52
+ */
53
+ export function getTokenPrices(billing = {}) {
54
+ const prices = billing.tokenPrices || billing.token_prices;
55
+ if (!prices) return null;
56
+
57
+ const isCurrentFormat = Boolean(billing.tokenPrices);
58
+ return {
59
+ input_price: prices.inputPrice ?? prices.input_price,
60
+ output_price: prices.outputPrice ?? prices.output_price,
61
+ cache_price: prices.cachePrice ?? prices.cache_price,
62
+ cache_read_price: prices.cacheReadPrice ?? prices.cache_read_price,
63
+ cache_write_price: prices.cacheWritePrice ?? prices.cache_write_price,
64
+ batch_size: prices.batchSize ?? prices.batch_size,
65
+ context_max: prices.contextMax ?? prices.context_max,
66
+ max_prompt_tokens: prices.maxPromptTokens ?? prices.max_prompt_tokens,
67
+ long_context: prices.longContext ?? prices.long_context,
68
+ price_scale: isCurrentFormat ? 'cents' : 'sdk',
69
+ };
70
+ }
71
+
47
72
  /**
48
73
  * 合併 SDK 模型資料與本機增強資料
49
74
  * @param {object} sdkModel
@@ -62,6 +87,7 @@ export function enrichModel(sdkModel) {
62
87
  notes: enhancement.notes,
63
88
  contextWindow: formatTokenCount(limits.max_context_window_tokens),
64
89
  maxOutputTokens: formatTokenCount(limits.max_output_tokens),
90
+ tokenPrices: getTokenPrices(sdkModel.billing),
65
91
  };
66
92
  }
67
93
 
@@ -69,13 +95,13 @@ export function enrichModel(sdkModel) {
69
95
  * 格式化價格(將 SDK 內部單位轉換為美元 / 1M tokens)
70
96
  * @param {number} price
71
97
  * @param {number} batchSize
98
+ * @param {'sdk' | 'cents'} priceScale
72
99
  * @returns {string}
73
100
  */
74
- export function formatPrice(price, batchSize) {
101
+ export function formatPrice(price, batchSize, priceScale = 'sdk') {
75
102
  if (price === undefined || price === null) return '—';
76
103
  if (!batchSize || batchSize === 0 || price === 0) return '—';
77
- // SDK 內部單位為 10^-11 美元 / batch_size tokens
78
- const dollars = price / 100_000_000_000;
104
+ const dollars = priceScale === 'cents' ? price / 100 : price / 100_000_000_000;
79
105
  return `$${dollars.toFixed(2)}`;
80
106
  }
81
107
 
@@ -18,7 +18,7 @@ const AI_TIMEOUT_MS = 150000;
18
18
  */
19
19
  export class AIAnalyzer {
20
20
  constructor(config = {}) {
21
- this.model = config.model || 'gpt-4.1';
21
+ this.model = config.model || 'claude-haiku-4.5';
22
22
  this._client = null; // 複用同一個 CopilotClient,避免重複啟動子程序
23
23
  }
24
24