taiwan-invoice-skill 2.0.0 → 2.1.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.
package/README.md ADDED
@@ -0,0 +1,131 @@
1
+ # taiwan-invoice-skill
2
+
3
+ <p align="center">
4
+ <strong>台灣電子發票 AI 開發技能包</strong><br>
5
+ <sub>支援 ECPay 綠界 · SmilePay 速買配 · Amego 光貿</sub>
6
+ </p>
7
+
8
+ <p align="center">
9
+ <a href="https://www.npmjs.com/package/taiwan-invoice-skill"><img src="https://img.shields.io/npm/v/taiwan-invoice-skill?style=flat-square&logo=npm" alt="npm version"></a>
10
+ <a href="https://www.npmjs.com/package/taiwan-invoice-skill"><img src="https://img.shields.io/npm/dm/taiwan-invoice-skill?style=flat-square&label=downloads" alt="npm downloads"></a>
11
+ <img src="https://img.shields.io/badge/node-%3E%3D18-339933?style=flat-square&logo=node.js&logoColor=white" alt="Node.js">
12
+ <img src="https://img.shields.io/badge/platforms-14-blue?style=flat-square" alt="14 Platforms">
13
+ <a href="https://github.com/Moksa1123/taiwan-invoice/blob/main/LICENSE"><img src="https://img.shields.io/github/license/Moksa1123/taiwan-invoice?style=flat-square" alt="License"></a>
14
+ </p>
15
+
16
+ <p align="center">
17
+ <a href="https://paypal.me/cccsubcom"><img src="https://img.shields.io/badge/PayPal-支持開發-00457C?style=for-the-badge&logo=paypal&logoColor=white" alt="PayPal"></a>
18
+ </p>
19
+
20
+ ---
21
+
22
+ ## 安裝
23
+
24
+ ```bash
25
+ npm install -g taiwan-invoice-skill
26
+ ```
27
+
28
+ ---
29
+
30
+ ## 使用方式
31
+
32
+ ```bash
33
+ # 進入專案目錄
34
+ cd /path/to/your/project
35
+
36
+ # 選擇你的 AI 助手
37
+ taiwan-invoice init --ai claude # Claude Code
38
+ taiwan-invoice init --ai cursor # Cursor
39
+ taiwan-invoice init --ai windsurf # Windsurf
40
+ taiwan-invoice init --ai copilot # GitHub Copilot
41
+ taiwan-invoice init --ai antigravity # Antigravity
42
+ taiwan-invoice init --ai all # 全部安裝
43
+ ```
44
+
45
+ <details>
46
+ <summary>完整平台列表</summary>
47
+
48
+ ```bash
49
+ taiwan-invoice init --ai kiro # Kiro (AWS)
50
+ taiwan-invoice init --ai codex # Codex CLI (OpenAI)
51
+ taiwan-invoice init --ai qoder # Qoder
52
+ taiwan-invoice init --ai roocode # Roo Code
53
+ taiwan-invoice init --ai gemini # Gemini CLI
54
+ taiwan-invoice init --ai trae # Trae (ByteDance)
55
+ taiwan-invoice init --ai opencode # OpenCode
56
+ taiwan-invoice init --ai continue # Continue
57
+ taiwan-invoice init --ai codebuddy # CodeBuddy (Tencent)
58
+ ```
59
+
60
+ </details>
61
+
62
+ ---
63
+
64
+ ## 其他指令
65
+
66
+ ```bash
67
+ taiwan-invoice list # 列出支援平台
68
+ taiwan-invoice info # 顯示技能資訊
69
+ taiwan-invoice versions # 列出可用版本
70
+ taiwan-invoice update # 檢查更新
71
+ ```
72
+
73
+ ### 選項
74
+
75
+ ```bash
76
+ taiwan-invoice init --offline # 跳過 GitHub 下載,使用內建資源
77
+ taiwan-invoice init --force # 覆蓋現有檔案
78
+ taiwan-invoice init --global # 安裝到全域目錄
79
+ ```
80
+
81
+ ---
82
+
83
+ ## 運作原理
84
+
85
+ `taiwan-invoice init` 預設會從 GitHub 下載最新版本。如果下載失敗(網路錯誤、速率限制),會自動使用 CLI 內建的資源。
86
+
87
+ 使用 `--offline` 可跳過 GitHub 下載,直接使用內建資源。
88
+
89
+ ---
90
+
91
+ ## 支援平台
92
+
93
+ | 平台 | 說明 | 啟動方式 |
94
+ |------|------|----------|
95
+ | **Claude Code** | Anthropic 官方 CLI | 自動 |
96
+ | **Cursor** | AI 程式編輯器 | `/taiwan-invoice` |
97
+ | **Windsurf** | Codeium 編輯器 | 自動 |
98
+ | **Copilot** | GitHub Copilot | `/taiwan-invoice` |
99
+ | **Antigravity** | Google AI 助手 | 自動 |
100
+ | **Kiro** | AWS AI 助手 | `/taiwan-invoice` |
101
+ | **Codex** | OpenAI CLI | 自動 |
102
+ | **Qoder** | Qodo AI 助手 | 自動 |
103
+ | **RooCode** | VSCode 擴充 | `/taiwan-invoice` |
104
+ | **Gemini CLI** | Google Gemini | 自動 |
105
+ | **Trae** | ByteDance AI | 自動 |
106
+ | **OpenCode** | 開源 AI 助手 | 自動 |
107
+ | **Continue** | 開源 AI 助手 | 自動 |
108
+ | **CodeBuddy** | Tencent AI | 自動 |
109
+
110
+ ---
111
+
112
+ ## 加值中心
113
+
114
+ | 加值中心 | 驗證方式 | 特點 |
115
+ |----------|----------|------|
116
+ | **ECPay 綠界** | AES-128-CBC 加密 | 市佔率高,文件完整 |
117
+ | **SmilePay 速買配** | URL 參數簽章 | 雙協定支援,整合簡單 |
118
+ | **Amego 光貿** | MD5 簽章 (MIG 4.0) | API 設計乾淨 |
119
+
120
+ ---
121
+
122
+ ## 授權
123
+
124
+ [MIT License](https://github.com/Moksa1123/taiwan-invoice/blob/main/LICENSE)
125
+
126
+ ---
127
+
128
+ <p align="center">
129
+ <sub>Made by <strong>Moksa</strong></sub><br>
130
+ <sub>service@moksaweb.com</sub>
131
+ </p>
@@ -0,0 +1,85 @@
1
+ ## When to Apply
2
+
3
+ Reference these guidelines when:
4
+ - Developing Taiwan E-Invoice issuance functionality
5
+ - Integrating ECPay, SmilePay, or Amego APIs
6
+ - Implementing B2C or B2B invoice logic
7
+ - Handling invoice printing, void, and allowance
8
+ - Troubleshooting invoice API integration issues
9
+
10
+ ## Provider Quick Reference
11
+
12
+ | Priority | Task | Impact | Provider |
13
+ |----------|------|--------|----------|
14
+ | 1 | Amount Calculation | CRITICAL | All |
15
+ | 2 | Encryption/Signature | CRITICAL | All |
16
+ | 3 | B2B vs B2C Logic | HIGH | All |
17
+ | 4 | Print Response Handling | HIGH | All |
18
+ | 5 | Provider Binding | MEDIUM | All |
19
+ | 6 | Error Handling | MEDIUM | All |
20
+ | 7 | Carrier/Donation | LOW | B2C only |
21
+
22
+ ## Quick Reference
23
+
24
+ ### 1. Amount Calculation (CRITICAL)
25
+
26
+ - `b2c-tax-inclusive` - B2C uses tax-inclusive total
27
+ - `b2b-split-tax` - B2B requires pre-tax + tax split
28
+ - `round-tax` - Round tax: `Math.round(total - (total / 1.05))`
29
+ - `salesamount` - ECPay/Amego: Use SalesAmount for pre-tax
30
+
31
+ ### 2. Encryption/Signature (CRITICAL)
32
+
33
+ - `ecpay-aes` - ECPay: AES-128-CBC with HashKey/HashIV
34
+ - `smilepay-verify` - SmilePay: Grvc + Verify_key params
35
+ - `amego-md5` - Amego: MD5(data + time + appKey)
36
+ - `url-encode` - Always URL encode before encryption
37
+
38
+ ### 3. B2B vs B2C Logic (HIGH)
39
+
40
+ - `buyer-id-b2c` - B2C: BuyerIdentifier = "0000000000"
41
+ - `buyer-id-b2b` - B2B: BuyerIdentifier = actual 8-digit tax ID
42
+ - `no-carrier-b2b` - B2B: Cannot use carrier or donation
43
+ - `validate-taxid` - Validate 8-digit tax ID format
44
+
45
+ ### 4. Print Response Handling (HIGH)
46
+
47
+ - `ecpay-html` - ECPay: Returns HTML, use window.document.write
48
+ - `smilepay-redirect` - SmilePay: Returns URL, use window.open
49
+ - `amego-pdf` - Amego: Returns PDF URL, use window.open
50
+ - `form-submit` - Some APIs require form POST submission
51
+
52
+ ### 5. Provider Binding (MEDIUM)
53
+
54
+ - `save-provider` - Save invoiceProvider when issuing
55
+ - `save-random` - Save invoiceRandomNum for printing
56
+ - `match-provider` - Use issuing provider for print/void
57
+
58
+ ### 6. Error Handling (MEDIUM)
59
+
60
+ - `log-raw-response` - Log complete raw response for debugging
61
+ - `ecpay-codes` - ECPay: Check RtnCode and RtnMsg
62
+ - `smilepay-codes` - SmilePay: Check Status field
63
+ - `amego-codes` - Amego: Check Code and Message
64
+
65
+ ### 7. Carrier/Donation (B2C only)
66
+
67
+ - `carrier-mobile` - Mobile barcode: /XXXXXXX format
68
+ - `carrier-npc` - Natural person certificate
69
+ - `donation-code` - Donation: 3-7 digit love code
70
+ - `mutual-exclusive` - Carrier and donation are mutually exclusive
71
+
72
+ ## Test Credentials
73
+
74
+ | Provider | Key Info |
75
+ |----------|----------|
76
+ | ECPay | MerchantID: 2000132, Stage URL |
77
+ | SmilePay | Grvc: SEI1000034, Test Tax ID: 80129529 |
78
+ | Amego | Tax ID: 12345678, test@amego.tw |
79
+
80
+ ## How to Use
81
+
82
+ See the full skill documentation for detailed API references and code examples.
83
+
84
+ ---
85
+
@@ -1,12 +1,13 @@
1
1
  {
2
2
  "platform": "antigravity",
3
- "displayName": "Google Antigravity",
3
+ "displayName": "Antigravity / Generic Agent",
4
4
  "installType": "full",
5
5
  "folderStructure": {
6
6
  "root": ".agent",
7
7
  "skillPath": "skills/taiwan-invoice",
8
8
  "filename": "SKILL.md"
9
9
  },
10
+ "scriptPath": "skills/taiwan-invoice/scripts",
10
11
  "frontmatter": {
11
12
  "name": "taiwan-invoice",
12
13
  "description": "Taiwan E-Invoice API integration specialist for ECPay, SmilePay, and Amego. Provides B2C/B2B invoice issuance, void, allowance, query, and print functionality."
@@ -14,8 +15,10 @@
14
15
  "sections": {
15
16
  "examples": true,
16
17
  "references": true,
17
- "scripts": true
18
+ "scripts": true,
19
+ "quickReference": false
18
20
  },
19
21
  "title": "Taiwan E-Invoice Skill",
20
- "description": "Comprehensive guide for Taiwan E-Invoice API integration. Supports ECPay, SmilePay, and Amego providers with B2C/B2B invoice operations."
22
+ "description": "Comprehensive guide for Taiwan E-Invoice API integration. Supports ECPay, SmilePay, and Amego providers with B2C/B2B invoice operations.",
23
+ "skillOrWorkflow": "Skill"
21
24
  }
@@ -7,6 +7,7 @@
7
7
  "skillPath": "skills/taiwan-invoice",
8
8
  "filename": "SKILL.md"
9
9
  },
10
+ "scriptPath": "skills/taiwan-invoice/scripts",
10
11
  "frontmatter": {
11
12
  "name": "taiwan-invoice",
12
13
  "description": "Taiwan E-Invoice API integration specialist for ECPay, SmilePay, and Amego. Provides B2C/B2B invoice issuance, void, allowance, query, and print functionality. Includes encryption implementations (AES-128-CBC, MD5), tax calculations, and complete API specifications.",
@@ -15,8 +16,10 @@
15
16
  "sections": {
16
17
  "examples": true,
17
18
  "references": true,
18
- "scripts": true
19
+ "scripts": true,
20
+ "quickReference": true
19
21
  },
20
22
  "title": "Taiwan E-Invoice Skill",
21
- "description": "Comprehensive guide for Taiwan E-Invoice API integration. Supports ECPay, SmilePay, and Amego providers with B2C/B2B invoice operations."
23
+ "description": "Comprehensive guide for Taiwan E-Invoice API integration. Supports ECPay, SmilePay, and Amego providers with B2C/B2B invoice operations.",
24
+ "skillOrWorkflow": "Skill"
22
25
  }
@@ -7,12 +7,15 @@
7
7
  "skillPath": "skills/taiwan-invoice",
8
8
  "filename": "SKILL.md"
9
9
  },
10
+ "scriptPath": "skills/taiwan-invoice/scripts",
10
11
  "frontmatter": null,
11
12
  "sections": {
12
13
  "examples": true,
13
14
  "references": true,
14
- "scripts": true
15
+ "scripts": true,
16
+ "quickReference": false
15
17
  },
16
18
  "title": "Taiwan E-Invoice Skill",
17
- "description": "Comprehensive guide for Taiwan E-Invoice API integration. Supports ECPay, SmilePay, and Amego providers with B2C/B2B invoice operations."
19
+ "description": "Comprehensive guide for Taiwan E-Invoice API integration. Supports ECPay, SmilePay, and Amego providers with B2C/B2B invoice operations.",
20
+ "skillOrWorkflow": "Skill"
18
21
  }
@@ -7,6 +7,7 @@
7
7
  "skillPath": "skills/taiwan-invoice",
8
8
  "filename": "SKILL.md"
9
9
  },
10
+ "scriptPath": "skills/taiwan-invoice/scripts",
10
11
  "frontmatter": {
11
12
  "name": "taiwan-invoice",
12
13
  "description": "Taiwan E-Invoice API integration specialist for ECPay, SmilePay, and Amego."
@@ -14,8 +15,10 @@
14
15
  "sections": {
15
16
  "examples": true,
16
17
  "references": true,
17
- "scripts": true
18
+ "scripts": true,
19
+ "quickReference": false
18
20
  },
19
21
  "title": "Taiwan E-Invoice Skill",
20
- "description": "Comprehensive guide for Taiwan E-Invoice API integration. Supports ECPay, SmilePay, and Amego providers with B2C/B2B invoice operations."
22
+ "description": "Comprehensive guide for Taiwan E-Invoice API integration. Supports ECPay, SmilePay, and Amego providers with B2C/B2B invoice operations.",
23
+ "skillOrWorkflow": "Skill"
21
24
  }
@@ -7,6 +7,7 @@
7
7
  "skillPath": "skills/taiwan-invoice",
8
8
  "filename": "SKILL.md"
9
9
  },
10
+ "scriptPath": "skills/taiwan-invoice/scripts",
10
11
  "frontmatter": {
11
12
  "name": "taiwan-invoice",
12
13
  "description": "Taiwan E-Invoice API integration specialist for ECPay, SmilePay, and Amego."
@@ -14,8 +15,10 @@
14
15
  "sections": {
15
16
  "examples": true,
16
17
  "references": true,
17
- "scripts": true
18
+ "scripts": true,
19
+ "quickReference": false
18
20
  },
19
21
  "title": "Taiwan E-Invoice Skill",
20
- "description": "Comprehensive guide for Taiwan E-Invoice API integration. Supports ECPay, SmilePay, and Amego providers with B2C/B2B invoice operations."
22
+ "description": "Comprehensive guide for Taiwan E-Invoice API integration. Supports ECPay, SmilePay, and Amego providers with B2C/B2B invoice operations.",
23
+ "skillOrWorkflow": "Skill"
21
24
  }
@@ -7,12 +7,15 @@
7
7
  "skillPath": "prompts/taiwan-invoice",
8
8
  "filename": "SKILL.md"
9
9
  },
10
+ "scriptPath": "prompts/taiwan-invoice/scripts",
10
11
  "frontmatter": null,
11
12
  "sections": {
12
13
  "examples": true,
13
14
  "references": true,
14
- "scripts": true
15
+ "scripts": true,
16
+ "quickReference": false
15
17
  },
16
18
  "title": "Taiwan E-Invoice Skill",
17
- "description": "Comprehensive guide for Taiwan E-Invoice API integration. Supports ECPay, SmilePay, and Amego providers with B2C/B2B invoice operations."
19
+ "description": "Comprehensive guide for Taiwan E-Invoice API integration. Supports ECPay, SmilePay, and Amego providers with B2C/B2B invoice operations.",
20
+ "skillOrWorkflow": "Skill"
18
21
  }
@@ -7,6 +7,7 @@
7
7
  "skillPath": "skills/taiwan-invoice",
8
8
  "filename": "SKILL.md"
9
9
  },
10
+ "scriptPath": "skills/taiwan-invoice/scripts",
10
11
  "frontmatter": {
11
12
  "name": "taiwan-invoice",
12
13
  "description": "Taiwan E-Invoice API integration specialist for ECPay, SmilePay, and Amego. Provides B2C/B2B invoice issuance, void, allowance, query, and print functionality. Includes encryption implementations (AES-128-CBC, MD5), tax calculations, and complete API specifications."
@@ -14,8 +15,10 @@
14
15
  "sections": {
15
16
  "examples": true,
16
17
  "references": true,
17
- "scripts": true
18
+ "scripts": true,
19
+ "quickReference": false
18
20
  },
19
21
  "title": "Taiwan E-Invoice Skill",
20
- "description": "Comprehensive guide for Taiwan E-Invoice API integration. Supports ECPay, SmilePay, and Amego providers with B2C/B2B invoice operations."
22
+ "description": "Comprehensive guide for Taiwan E-Invoice API integration. Supports ECPay, SmilePay, and Amego providers with B2C/B2B invoice operations.",
23
+ "skillOrWorkflow": "Skill"
21
24
  }
@@ -7,6 +7,7 @@
7
7
  "skillPath": "skills/taiwan-invoice",
8
8
  "filename": "SKILL.md"
9
9
  },
10
+ "scriptPath": "skills/taiwan-invoice/scripts",
10
11
  "frontmatter": {
11
12
  "name": "taiwan-invoice",
12
13
  "description": "Taiwan E-Invoice API integration specialist for ECPay, SmilePay, and Amego."
@@ -14,8 +15,10 @@
14
15
  "sections": {
15
16
  "examples": true,
16
17
  "references": true,
17
- "scripts": true
18
+ "scripts": true,
19
+ "quickReference": false
18
20
  },
19
21
  "title": "Taiwan E-Invoice Skill",
20
- "description": "Comprehensive guide for Taiwan E-Invoice API integration. Supports ECPay, SmilePay, and Amego providers with B2C/B2B invoice operations."
22
+ "description": "Comprehensive guide for Taiwan E-Invoice API integration. Supports ECPay, SmilePay, and Amego providers with B2C/B2B invoice operations.",
23
+ "skillOrWorkflow": "Skill"
21
24
  }
@@ -7,12 +7,15 @@
7
7
  "skillPath": "steering/taiwan-invoice",
8
8
  "filename": "SKILL.md"
9
9
  },
10
+ "scriptPath": "steering/taiwan-invoice/scripts",
10
11
  "frontmatter": null,
11
12
  "sections": {
12
13
  "examples": true,
13
14
  "references": true,
14
- "scripts": true
15
+ "scripts": true,
16
+ "quickReference": false
15
17
  },
16
18
  "title": "Taiwan E-Invoice Skill",
17
- "description": "Comprehensive guide for Taiwan E-Invoice API integration. Supports ECPay, SmilePay, and Amego providers with B2C/B2B invoice operations."
19
+ "description": "Comprehensive guide for Taiwan E-Invoice API integration. Supports ECPay, SmilePay, and Amego providers with B2C/B2B invoice operations.",
20
+ "skillOrWorkflow": "Skill"
18
21
  }
@@ -7,12 +7,15 @@
7
7
  "skillPath": "skills/taiwan-invoice",
8
8
  "filename": "SKILL.md"
9
9
  },
10
+ "scriptPath": "skills/taiwan-invoice/scripts",
10
11
  "frontmatter": null,
11
12
  "sections": {
12
13
  "examples": true,
13
14
  "references": true,
14
- "scripts": true
15
+ "scripts": true,
16
+ "quickReference": false
15
17
  },
16
18
  "title": "Taiwan E-Invoice Skill",
17
- "description": "Comprehensive guide for Taiwan E-Invoice API integration. Supports ECPay, SmilePay, and Amego providers with B2C/B2B invoice operations."
19
+ "description": "Comprehensive guide for Taiwan E-Invoice API integration. Supports ECPay, SmilePay, and Amego providers with B2C/B2B invoice operations.",
20
+ "skillOrWorkflow": "Skill"
18
21
  }
@@ -7,12 +7,15 @@
7
7
  "skillPath": "rules/taiwan-invoice",
8
8
  "filename": "SKILL.md"
9
9
  },
10
+ "scriptPath": "rules/taiwan-invoice/scripts",
10
11
  "frontmatter": null,
11
12
  "sections": {
12
13
  "examples": true,
13
14
  "references": true,
14
- "scripts": true
15
+ "scripts": true,
16
+ "quickReference": false
15
17
  },
16
18
  "title": "Taiwan E-Invoice Skill",
17
- "description": "Comprehensive guide for Taiwan E-Invoice API integration. Supports ECPay, SmilePay, and Amego providers with B2C/B2B invoice operations."
19
+ "description": "Comprehensive guide for Taiwan E-Invoice API integration. Supports ECPay, SmilePay, and Amego providers with B2C/B2B invoice operations.",
20
+ "skillOrWorkflow": "Skill"
18
21
  }
@@ -7,12 +7,15 @@
7
7
  "skillPath": "commands/taiwan-invoice",
8
8
  "filename": "SKILL.md"
9
9
  },
10
+ "scriptPath": "commands/taiwan-invoice/scripts",
10
11
  "frontmatter": null,
11
12
  "sections": {
12
13
  "examples": true,
13
14
  "references": true,
14
- "scripts": true
15
+ "scripts": true,
16
+ "quickReference": false
15
17
  },
16
18
  "title": "Taiwan E-Invoice Skill",
17
- "description": "Comprehensive guide for Taiwan E-Invoice API integration. Supports ECPay, SmilePay, and Amego providers with B2C/B2B invoice operations."
19
+ "description": "Comprehensive guide for Taiwan E-Invoice API integration. Supports ECPay, SmilePay, and Amego providers with B2C/B2B invoice operations.",
20
+ "skillOrWorkflow": "Skill"
18
21
  }
@@ -7,12 +7,15 @@
7
7
  "skillPath": "skills/taiwan-invoice",
8
8
  "filename": "SKILL.md"
9
9
  },
10
+ "scriptPath": "skills/taiwan-invoice/scripts",
10
11
  "frontmatter": null,
11
12
  "sections": {
12
13
  "examples": true,
13
14
  "references": true,
14
- "scripts": true
15
+ "scripts": true,
16
+ "quickReference": false
15
17
  },
16
18
  "title": "Taiwan E-Invoice Skill",
17
- "description": "Comprehensive guide for Taiwan E-Invoice API integration. Supports ECPay, SmilePay, and Amego providers with B2C/B2B invoice operations."
19
+ "description": "Comprehensive guide for Taiwan E-Invoice API integration. Supports ECPay, SmilePay, and Amego providers with B2C/B2B invoice operations.",
20
+ "skillOrWorkflow": "Skill"
18
21
  }
@@ -7,6 +7,7 @@
7
7
  "skillPath": "skills/taiwan-invoice",
8
8
  "filename": "SKILL.md"
9
9
  },
10
+ "scriptPath": "skills/taiwan-invoice/scripts",
10
11
  "frontmatter": {
11
12
  "name": "taiwan-invoice",
12
13
  "description": "Taiwan E-Invoice API integration specialist for ECPay, SmilePay, and Amego. Provides B2C/B2B invoice issuance, void, allowance, query, and print functionality."
@@ -14,8 +15,10 @@
14
15
  "sections": {
15
16
  "examples": true,
16
17
  "references": true,
17
- "scripts": true
18
+ "scripts": true,
19
+ "quickReference": false
18
20
  },
19
21
  "title": "Taiwan E-Invoice Skill",
20
- "description": "Comprehensive guide for Taiwan E-Invoice API integration. Supports ECPay, SmilePay, and Amego providers with B2C/B2B invoice operations."
22
+ "description": "Comprehensive guide for Taiwan E-Invoice API integration. Supports ECPay, SmilePay, and Amego providers with B2C/B2B invoice operations.",
23
+ "skillOrWorkflow": "Skill"
21
24
  }
package/dist/index.js CHANGED
@@ -921,8 +921,8 @@ var require_command = __commonJS({
921
921
  "node_modules/commander/lib/command.js"(exports2) {
922
922
  var EventEmitter = require("events").EventEmitter;
923
923
  var childProcess = require("child_process");
924
- var path = require("path");
925
- var fs = require("fs");
924
+ var path3 = require("path");
925
+ var fs3 = require("fs");
926
926
  var process2 = require("process");
927
927
  var { Argument: Argument2, humanReadableArgName } = require_argument();
928
928
  var { CommanderError: CommanderError2 } = require_error();
@@ -1745,10 +1745,10 @@ Expecting one of '${allowedValues.join("', '")}'`);
1745
1745
  let launchWithNode = false;
1746
1746
  const sourceExt = [".js", ".ts", ".tsx", ".mjs", ".cjs"];
1747
1747
  function findFile(baseDir, baseName) {
1748
- const localBin = path.resolve(baseDir, baseName);
1749
- if (fs.existsSync(localBin)) return localBin;
1750
- if (sourceExt.includes(path.extname(baseName))) return void 0;
1751
- const foundExt = sourceExt.find((ext) => fs.existsSync(`${localBin}${ext}`));
1748
+ const localBin = path3.resolve(baseDir, baseName);
1749
+ if (fs3.existsSync(localBin)) return localBin;
1750
+ if (sourceExt.includes(path3.extname(baseName))) return void 0;
1751
+ const foundExt = sourceExt.find((ext) => fs3.existsSync(`${localBin}${ext}`));
1752
1752
  if (foundExt) return `${localBin}${foundExt}`;
1753
1753
  return void 0;
1754
1754
  }
@@ -1759,23 +1759,23 @@ Expecting one of '${allowedValues.join("', '")}'`);
1759
1759
  if (this._scriptPath) {
1760
1760
  let resolvedScriptPath;
1761
1761
  try {
1762
- resolvedScriptPath = fs.realpathSync(this._scriptPath);
1762
+ resolvedScriptPath = fs3.realpathSync(this._scriptPath);
1763
1763
  } catch (err) {
1764
1764
  resolvedScriptPath = this._scriptPath;
1765
1765
  }
1766
- executableDir = path.resolve(path.dirname(resolvedScriptPath), executableDir);
1766
+ executableDir = path3.resolve(path3.dirname(resolvedScriptPath), executableDir);
1767
1767
  }
1768
1768
  if (executableDir) {
1769
1769
  let localFile = findFile(executableDir, executableFile);
1770
1770
  if (!localFile && !subcommand._executableFile && this._scriptPath) {
1771
- const legacyName = path.basename(this._scriptPath, path.extname(this._scriptPath));
1771
+ const legacyName = path3.basename(this._scriptPath, path3.extname(this._scriptPath));
1772
1772
  if (legacyName !== this._name) {
1773
1773
  localFile = findFile(executableDir, `${legacyName}-${subcommand._name}`);
1774
1774
  }
1775
1775
  }
1776
1776
  executableFile = localFile || executableFile;
1777
1777
  }
1778
- launchWithNode = sourceExt.includes(path.extname(executableFile));
1778
+ launchWithNode = sourceExt.includes(path3.extname(executableFile));
1779
1779
  let proc;
1780
1780
  if (process2.platform !== "win32") {
1781
1781
  if (launchWithNode) {
@@ -2558,7 +2558,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
2558
2558
  * @return {Command}
2559
2559
  */
2560
2560
  nameFromFilename(filename) {
2561
- this._name = path.basename(filename, path.extname(filename));
2561
+ this._name = path3.basename(filename, path3.extname(filename));
2562
2562
  return this;
2563
2563
  }
2564
2564
  /**
@@ -2572,9 +2572,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
2572
2572
  * @param {string} [path]
2573
2573
  * @return {string|null|Command}
2574
2574
  */
2575
- executableDir(path2) {
2576
- if (path2 === void 0) return this._executableDir;
2577
- this._executableDir = path2;
2575
+ executableDir(path4) {
2576
+ if (path4 === void 0) return this._executableDir;
2577
+ this._executableDir = path4;
2578
2578
  return this;
2579
2579
  }
2580
2580
  /**
@@ -3634,15 +3634,15 @@ var require_route = __commonJS({
3634
3634
  };
3635
3635
  }
3636
3636
  function wrapConversion(toModel, graph) {
3637
- const path = [graph[toModel].parent, toModel];
3637
+ const path3 = [graph[toModel].parent, toModel];
3638
3638
  let fn = conversions[graph[toModel].parent][toModel];
3639
3639
  let cur = graph[toModel].parent;
3640
3640
  while (graph[cur].parent) {
3641
- path.unshift(graph[cur].parent);
3641
+ path3.unshift(graph[cur].parent);
3642
3642
  fn = link(conversions[graph[cur].parent][cur], fn);
3643
3643
  cur = graph[cur].parent;
3644
3644
  }
3645
- fn.conversion = path;
3645
+ fn.conversion = path3;
3646
3646
  return fn;
3647
3647
  }
3648
3648
  module2.exports = function(fromModel) {
@@ -3741,10 +3741,10 @@ var require_ansi_styles = __commonJS({
3741
3741
  };
3742
3742
  var ansi2ansi = (n) => n;
3743
3743
  var rgb2rgb = (r, g, b) => [r, g, b];
3744
- var setLazyProperty = (object, property, get) => {
3744
+ var setLazyProperty = (object, property, get2) => {
3745
3745
  Object.defineProperty(object, property, {
3746
3746
  get: () => {
3747
- const value = get();
3747
+ const value = get2();
3748
3748
  Object.defineProperty(object, property, {
3749
3749
  value,
3750
3750
  enumerable: true,
@@ -3882,7 +3882,7 @@ var require_has_flag = __commonJS({
3882
3882
  var require_supports_color = __commonJS({
3883
3883
  "node_modules/supports-color/index.js"(exports2, module2) {
3884
3884
  "use strict";
3885
- var os = require("os");
3885
+ var os2 = require("os");
3886
3886
  var tty = require("tty");
3887
3887
  var hasFlag = require_has_flag();
3888
3888
  var { env } = process;
@@ -3930,7 +3930,7 @@ var require_supports_color = __commonJS({
3930
3930
  return min;
3931
3931
  }
3932
3932
  if (process.platform === "win32") {
3933
- const osRelease = os.release().split(".");
3933
+ const osRelease = os2.release().split(".");
3934
3934
  if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) {
3935
3935
  return Number(osRelease[2]) >= 14931 ? 3 : 2;
3936
3936
  }
@@ -6800,7 +6800,7 @@ var require_buffer_list = __commonJS({
6800
6800
  }
6801
6801
  }, {
6802
6802
  key: "join",
6803
- value: function join3(s) {
6803
+ value: function join5(s) {
6804
6804
  if (this.length === 0) return "";
6805
6805
  var p = this.head;
6806
6806
  var ret = "" + p.data;
@@ -7377,7 +7377,7 @@ var require_stream_writable = __commonJS({
7377
7377
  // because otherwise some prototype manipulation in
7378
7378
  // userland will fail
7379
7379
  enumerable: false,
7380
- get: function get() {
7380
+ get: function get2() {
7381
7381
  return this._writableState && this._writableState.getBuffer();
7382
7382
  }
7383
7383
  });
@@ -7392,7 +7392,7 @@ var require_stream_writable = __commonJS({
7392
7392
  // because otherwise some prototype manipulation in
7393
7393
  // userland will fail
7394
7394
  enumerable: false,
7395
- get: function get() {
7395
+ get: function get2() {
7396
7396
  return this._writableState.highWaterMark;
7397
7397
  }
7398
7398
  });
@@ -7562,7 +7562,7 @@ var require_stream_writable = __commonJS({
7562
7562
  // because otherwise some prototype manipulation in
7563
7563
  // userland will fail
7564
7564
  enumerable: false,
7565
- get: function get() {
7565
+ get: function get2() {
7566
7566
  return this._writableState.length;
7567
7567
  }
7568
7568
  });
@@ -7635,7 +7635,7 @@ var require_stream_writable = __commonJS({
7635
7635
  // because otherwise some prototype manipulation in
7636
7636
  // userland will fail
7637
7637
  enumerable: false,
7638
- get: function get() {
7638
+ get: function get2() {
7639
7639
  if (this._writableState === void 0) {
7640
7640
  return false;
7641
7641
  }
@@ -7698,7 +7698,7 @@ var require_stream_duplex = __commonJS({
7698
7698
  // because otherwise some prototype manipulation in
7699
7699
  // userland will fail
7700
7700
  enumerable: false,
7701
- get: function get() {
7701
+ get: function get2() {
7702
7702
  return this._writableState.highWaterMark;
7703
7703
  }
7704
7704
  });
@@ -7707,7 +7707,7 @@ var require_stream_duplex = __commonJS({
7707
7707
  // because otherwise some prototype manipulation in
7708
7708
  // userland will fail
7709
7709
  enumerable: false,
7710
- get: function get() {
7710
+ get: function get2() {
7711
7711
  return this._writableState && this._writableState.getBuffer();
7712
7712
  }
7713
7713
  });
@@ -7716,7 +7716,7 @@ var require_stream_duplex = __commonJS({
7716
7716
  // because otherwise some prototype manipulation in
7717
7717
  // userland will fail
7718
7718
  enumerable: false,
7719
- get: function get() {
7719
+ get: function get2() {
7720
7720
  return this._writableState.length;
7721
7721
  }
7722
7722
  });
@@ -7732,7 +7732,7 @@ var require_stream_duplex = __commonJS({
7732
7732
  // because otherwise some prototype manipulation in
7733
7733
  // userland will fail
7734
7734
  enumerable: false,
7735
- get: function get() {
7735
+ get: function get2() {
7736
7736
  if (this._readableState === void 0 || this._writableState === void 0) {
7737
7737
  return false;
7738
7738
  }
@@ -8540,7 +8540,7 @@ var require_stream_readable = __commonJS({
8540
8540
  // because otherwise some prototype manipulation in
8541
8541
  // userland will fail
8542
8542
  enumerable: false,
8543
- get: function get() {
8543
+ get: function get2() {
8544
8544
  if (this._readableState === void 0) {
8545
8545
  return false;
8546
8546
  }
@@ -8823,7 +8823,7 @@ var require_stream_readable = __commonJS({
8823
8823
  if (readable === src) {
8824
8824
  if (unpipeInfo && unpipeInfo.hasUnpiped === false) {
8825
8825
  unpipeInfo.hasUnpiped = true;
8826
- cleanup();
8826
+ cleanup2();
8827
8827
  }
8828
8828
  }
8829
8829
  }
@@ -8834,7 +8834,7 @@ var require_stream_readable = __commonJS({
8834
8834
  var ondrain = pipeOnDrain(src);
8835
8835
  dest.on("drain", ondrain);
8836
8836
  var cleanedUp = false;
8837
- function cleanup() {
8837
+ function cleanup2() {
8838
8838
  debug("cleanup");
8839
8839
  dest.removeListener("close", onclose);
8840
8840
  dest.removeListener("finish", onfinish);
@@ -9081,7 +9081,7 @@ var require_stream_readable = __commonJS({
9081
9081
  // because otherwise some prototype manipulation in
9082
9082
  // userland will fail
9083
9083
  enumerable: false,
9084
- get: function get() {
9084
+ get: function get2() {
9085
9085
  return this._readableState.highWaterMark;
9086
9086
  }
9087
9087
  });
@@ -9090,7 +9090,7 @@ var require_stream_readable = __commonJS({
9090
9090
  // because otherwise some prototype manipulation in
9091
9091
  // userland will fail
9092
9092
  enumerable: false,
9093
- get: function get() {
9093
+ get: function get2() {
9094
9094
  return this._readableState && this._readableState.buffer;
9095
9095
  }
9096
9096
  });
@@ -9099,7 +9099,7 @@ var require_stream_readable = __commonJS({
9099
9099
  // because otherwise some prototype manipulation in
9100
9100
  // userland will fail
9101
9101
  enumerable: false,
9102
- get: function get() {
9102
+ get: function get2() {
9103
9103
  return this._readableState.flowing;
9104
9104
  },
9105
9105
  set: function set(state) {
@@ -9114,7 +9114,7 @@ var require_stream_readable = __commonJS({
9114
9114
  // because otherwise some prototype manipulation in
9115
9115
  // userland will fail
9116
9116
  enumerable: false,
9117
- get: function get() {
9117
+ get: function get2() {
9118
9118
  return this._readableState.length;
9119
9119
  }
9120
9120
  });
@@ -9440,7 +9440,7 @@ var require_BufferList = __commonJS({
9440
9440
  }
9441
9441
  return offset;
9442
9442
  };
9443
- BufferList.prototype.get = function get(index) {
9443
+ BufferList.prototype.get = function get2(index) {
9444
9444
  if (index > this.length || index < 0) {
9445
9445
  return void 0;
9446
9446
  }
@@ -14965,6 +14965,8 @@ var {
14965
14965
  var import_chalk2 = __toESM(require_source());
14966
14966
  var import_ora = __toESM(require_ora());
14967
14967
  var import_prompts = __toESM(require_prompts3());
14968
+ var path2 = __toESM(require("path"));
14969
+ var os = __toESM(require("os"));
14968
14970
 
14969
14971
  // src/types/index.ts
14970
14972
  var AI_TYPES = [
@@ -14984,6 +14986,22 @@ var AI_TYPES = [
14984
14986
  "codebuddy",
14985
14987
  "all"
14986
14988
  ];
14989
+ var AI_FOLDERS = {
14990
+ claude: [".claude"],
14991
+ cursor: [".cursor"],
14992
+ windsurf: [".windsurf"],
14993
+ antigravity: [".agent"],
14994
+ copilot: [".github"],
14995
+ kiro: [".kiro"],
14996
+ codex: [".codex"],
14997
+ qoder: [".qoder"],
14998
+ roocode: [".roo"],
14999
+ gemini: [".gemini"],
15000
+ trae: [".trae"],
15001
+ opencode: [".opencode"],
15002
+ continue: [".continue"],
15003
+ codebuddy: [".codebuddy"]
15004
+ };
14987
15005
 
14988
15006
  // src/utils/template.ts
14989
15007
  var import_promises = require("node:fs/promises");
@@ -14995,7 +15013,7 @@ var AI_TO_PLATFORM = {
14995
15013
  claude: "claude",
14996
15014
  cursor: "cursor",
14997
15015
  windsurf: "windsurf",
14998
- antigravity: "antigravity",
15016
+ antigravity: "agent",
14999
15017
  copilot: "copilot",
15000
15018
  kiro: "kiro",
15001
15019
  codex: "codex",
@@ -15007,9 +15025,9 @@ var AI_TO_PLATFORM = {
15007
15025
  continue: "continue",
15008
15026
  codebuddy: "codebuddy"
15009
15027
  };
15010
- async function exists(path) {
15028
+ async function exists(path3) {
15011
15029
  try {
15012
- await (0, import_promises.access)(path);
15030
+ await (0, import_promises.access)(path3);
15013
15031
  return true;
15014
15032
  } catch {
15015
15033
  return false;
@@ -15045,6 +15063,13 @@ async function renderSkillFile(config) {
15045
15063
  let content = await loadTemplate("base/skill-content.md");
15046
15064
  const frontmatter = renderFrontmatter(config.frontmatter);
15047
15065
  content = content.replace(/\{\{TITLE\}\}/g, config.title).replace(/\{\{DESCRIPTION\}\}/g, config.description);
15066
+ if (config.sections.quickReference) {
15067
+ try {
15068
+ const quickRef = await loadTemplate("base/quick-reference.md");
15069
+ content = quickRef + "\n" + content;
15070
+ } catch {
15071
+ }
15072
+ }
15048
15073
  return frontmatter + content;
15049
15074
  }
15050
15075
  async function copyTaiwanInvoiceAssets(targetSkillDir, sections) {
@@ -15194,7 +15219,186 @@ ${msg}
15194
15219
  dim: (msg) => console.log(import_chalk.default.dim(msg))
15195
15220
  };
15196
15221
 
15222
+ // src/utils/github.ts
15223
+ var https = __toESM(require("https"));
15224
+ var fs = __toESM(require("fs"));
15225
+ var REPO_OWNER = "Moksa1123";
15226
+ var REPO_NAME = "taiwan-invoice";
15227
+ async function fetchReleases() {
15228
+ return new Promise((resolve, reject) => {
15229
+ const options = {
15230
+ hostname: "api.github.com",
15231
+ path: `/repos/${REPO_OWNER}/${REPO_NAME}/releases`,
15232
+ headers: {
15233
+ "User-Agent": "taiwan-invoice-skill-cli",
15234
+ "Accept": "application/vnd.github.v3+json"
15235
+ }
15236
+ };
15237
+ https.get(options, (res) => {
15238
+ let data = "";
15239
+ res.on("data", (chunk) => data += chunk);
15240
+ res.on("end", () => {
15241
+ if (res.statusCode === 200) {
15242
+ try {
15243
+ resolve(JSON.parse(data));
15244
+ } catch (e) {
15245
+ reject(new Error("Failed to parse GitHub response"));
15246
+ }
15247
+ } else if (res.statusCode === 404) {
15248
+ resolve([]);
15249
+ } else {
15250
+ reject(new Error(`GitHub API error: ${res.statusCode}`));
15251
+ }
15252
+ });
15253
+ }).on("error", reject);
15254
+ });
15255
+ }
15256
+ async function getLatestRelease() {
15257
+ const releases = await fetchReleases();
15258
+ return releases.length > 0 ? releases[0] : null;
15259
+ }
15260
+ async function downloadRelease(url, dest) {
15261
+ return new Promise((resolve, reject) => {
15262
+ const file = fs.createWriteStream(dest);
15263
+ const request = (downloadUrl) => {
15264
+ https.get(downloadUrl, {
15265
+ headers: {
15266
+ "User-Agent": "taiwan-invoice-skill-cli",
15267
+ "Accept": "application/octet-stream"
15268
+ }
15269
+ }, (res) => {
15270
+ if (res.statusCode === 302 || res.statusCode === 301) {
15271
+ const redirectUrl = res.headers.location;
15272
+ if (redirectUrl) {
15273
+ request(redirectUrl);
15274
+ return;
15275
+ }
15276
+ }
15277
+ if (res.statusCode !== 200) {
15278
+ file.close();
15279
+ fs.unlinkSync(dest);
15280
+ reject(new Error(`Download failed: ${res.statusCode}`));
15281
+ return;
15282
+ }
15283
+ res.pipe(file);
15284
+ file.on("finish", () => {
15285
+ file.close();
15286
+ resolve();
15287
+ });
15288
+ }).on("error", (err) => {
15289
+ file.close();
15290
+ fs.unlinkSync(dest);
15291
+ reject(err);
15292
+ });
15293
+ };
15294
+ request(url);
15295
+ });
15296
+ }
15297
+ function getSourceZipUrl(release) {
15298
+ return `https://github.com/${REPO_OWNER}/${REPO_NAME}/archive/refs/tags/${release.tag_name}.zip`;
15299
+ }
15300
+
15301
+ // src/utils/extract.ts
15302
+ var fs2 = __toESM(require("fs"));
15303
+ var path = __toESM(require("path"));
15304
+ var import_child_process = require("child_process");
15305
+ async function extractZip(zipPath, destDir) {
15306
+ if (!fs2.existsSync(destDir)) {
15307
+ fs2.mkdirSync(destDir, { recursive: true });
15308
+ }
15309
+ const isWindows = process.platform === "win32";
15310
+ if (isWindows) {
15311
+ const psCommand = `Expand-Archive -Path "${zipPath}" -DestinationPath "${destDir}" -Force`;
15312
+ (0, import_child_process.execSync)(`powershell -Command "${psCommand}"`, { stdio: "pipe" });
15313
+ } else {
15314
+ (0, import_child_process.execSync)(`unzip -o "${zipPath}" -d "${destDir}"`, { stdio: "pipe" });
15315
+ }
15316
+ }
15317
+ async function copyFolders(sourceDir, targetDir, aiType) {
15318
+ const copiedFolders = [];
15319
+ const foldersToCheck = AI_FOLDERS[aiType];
15320
+ for (const folder of foldersToCheck) {
15321
+ const sourcePath = path.join(sourceDir, folder);
15322
+ const targetPath = path.join(targetDir, folder);
15323
+ if (fs2.existsSync(sourcePath)) {
15324
+ copyDirRecursive(sourcePath, targetPath);
15325
+ copiedFolders.push(folder);
15326
+ }
15327
+ }
15328
+ return copiedFolders;
15329
+ }
15330
+ function copyDirRecursive(src, dest) {
15331
+ if (!fs2.existsSync(dest)) {
15332
+ fs2.mkdirSync(dest, { recursive: true });
15333
+ }
15334
+ const entries = fs2.readdirSync(src, { withFileTypes: true });
15335
+ for (const entry of entries) {
15336
+ const srcPath = path.join(src, entry.name);
15337
+ const destPath = path.join(dest, entry.name);
15338
+ if (entry.isDirectory()) {
15339
+ copyDirRecursive(srcPath, destPath);
15340
+ } else {
15341
+ fs2.copyFileSync(srcPath, destPath);
15342
+ }
15343
+ }
15344
+ }
15345
+ function findExtractedFolder(destDir) {
15346
+ const entries = fs2.readdirSync(destDir, { withFileTypes: true });
15347
+ const dirs = entries.filter((e) => e.isDirectory());
15348
+ const releaseDir = dirs.find(
15349
+ (d) => d.name.includes("taiwan-invoice") || d.name.startsWith("taiwan-invoice")
15350
+ );
15351
+ return releaseDir ? path.join(destDir, releaseDir.name) : null;
15352
+ }
15353
+ async function installFromZip(zipPath, targetDir, aiType) {
15354
+ const tempDir = path.join(path.dirname(zipPath), "taiwan-invoice-extracted");
15355
+ if (fs2.existsSync(tempDir)) {
15356
+ fs2.rmSync(tempDir, { recursive: true, force: true });
15357
+ }
15358
+ await extractZip(zipPath, tempDir);
15359
+ const extractedDir = findExtractedFolder(tempDir) || tempDir;
15360
+ const copiedFolders = await copyFolders(extractedDir, targetDir, aiType);
15361
+ return { copiedFolders, tempDir };
15362
+ }
15363
+ function cleanup(tempDir, zipPath) {
15364
+ if (tempDir && fs2.existsSync(tempDir)) {
15365
+ fs2.rmSync(tempDir, { recursive: true, force: true });
15366
+ }
15367
+ if (zipPath && fs2.existsSync(zipPath)) {
15368
+ fs2.unlinkSync(zipPath);
15369
+ }
15370
+ }
15371
+
15197
15372
  // src/commands/init.ts
15373
+ async function tryGitHubDownload(aiType, targetDir) {
15374
+ const spinner = (0, import_ora.default)("Checking for latest release on GitHub...").start();
15375
+ try {
15376
+ const release = await getLatestRelease();
15377
+ if (!release) {
15378
+ spinner.info("No releases found, using bundled assets");
15379
+ return { success: false, folders: [] };
15380
+ }
15381
+ spinner.text = `Found release: ${release.tag_name}`;
15382
+ const zipUrl = getSourceZipUrl(release);
15383
+ const tempDir = os.tmpdir();
15384
+ const zipPath = path2.join(tempDir, `taiwan-invoice-${release.tag_name}.zip`);
15385
+ spinner.text = "Downloading release...";
15386
+ await downloadRelease(zipUrl, zipPath);
15387
+ spinner.text = "Extracting and installing...";
15388
+ const { copiedFolders, tempDir: extractedDir } = await installFromZip(zipPath, targetDir, aiType);
15389
+ cleanup(extractedDir, zipPath);
15390
+ if (copiedFolders.length > 0) {
15391
+ spinner.succeed(`Installed from GitHub release ${release.tag_name}`);
15392
+ return { success: true, folders: copiedFolders };
15393
+ } else {
15394
+ spinner.info("No matching folders in release, using bundled assets");
15395
+ return { success: false, folders: [] };
15396
+ }
15397
+ } catch (error) {
15398
+ spinner.info("GitHub download failed, using bundled assets");
15399
+ return { success: false, folders: [] };
15400
+ }
15401
+ }
15198
15402
  async function initCommand(options) {
15199
15403
  logger.title("Taiwan Invoice Skill Installer");
15200
15404
  let aiType = options.ai;
@@ -15220,16 +15424,26 @@ async function initCommand(options) {
15220
15424
  aiType = response.aiType;
15221
15425
  }
15222
15426
  logger.info(`Installing for: ${import_chalk2.default.cyan(getAITypeDescription(aiType))}`);
15223
- const spinner = (0, import_ora.default)("Generating skill files from templates...").start();
15224
15427
  const cwd = process.cwd();
15225
15428
  let copiedFolders = [];
15429
+ let usedGitHub = false;
15226
15430
  try {
15227
- if (aiType === "all") {
15228
- copiedFolders = await generateAllPlatformFiles(cwd);
15229
- } else {
15230
- copiedFolders = await generatePlatformFiles(cwd, aiType);
15431
+ if (!options.offline && aiType !== "all") {
15432
+ const result = await tryGitHubDownload(aiType, cwd);
15433
+ if (result.success) {
15434
+ copiedFolders = result.folders;
15435
+ usedGitHub = true;
15436
+ }
15437
+ }
15438
+ if (!usedGitHub) {
15439
+ const spinner = (0, import_ora.default)("Generating skill files from bundled templates...").start();
15440
+ if (aiType === "all") {
15441
+ copiedFolders = await generateAllPlatformFiles(cwd);
15442
+ } else {
15443
+ copiedFolders = await generatePlatformFiles(cwd, aiType);
15444
+ }
15445
+ spinner.succeed("Generated from bundled templates!");
15231
15446
  }
15232
- spinner.succeed("Generated from templates!");
15233
15447
  console.log();
15234
15448
  logger.info("Installed folders:");
15235
15449
  copiedFolders.forEach((folder) => {
@@ -15243,7 +15457,7 @@ async function initCommand(options) {
15243
15457
  console.log(import_chalk2.default.dim(' 2. Try: "Help me integrate ECPay invoice API"'));
15244
15458
  console.log();
15245
15459
  } catch (error) {
15246
- spinner.fail("Installation failed");
15460
+ logger.error("Installation failed");
15247
15461
  if (error instanceof Error) {
15248
15462
  logger.error(error.message);
15249
15463
  }
@@ -15318,21 +15532,11 @@ async function infoCommand() {
15318
15532
  var import_chalk5 = __toESM(require_source());
15319
15533
  var import_ora2 = __toESM(require_ora());
15320
15534
  var VERSION2 = "2.0.0";
15321
- var REPO_API = "https://api.github.com/repos/Moksa1123/taiwan-invoice/releases";
15322
15535
  async function versionsCommand() {
15323
15536
  logger.title("Taiwan Invoice Skill - Available Versions");
15324
15537
  const spinner = (0, import_ora2.default)("Fetching releases from GitHub...").start();
15325
15538
  try {
15326
- const response = await fetch(REPO_API, {
15327
- headers: {
15328
- "Accept": "application/vnd.github.v3+json",
15329
- "User-Agent": "taiwan-invoice-skill-cli"
15330
- }
15331
- });
15332
- if (!response.ok) {
15333
- throw new Error(`GitHub API error: ${response.status}`);
15334
- }
15335
- const releases = await response.json();
15539
+ const releases = await fetchReleases();
15336
15540
  spinner.succeed("Fetched releases from GitHub");
15337
15541
  console.log();
15338
15542
  console.log(import_chalk5.default.cyan("Available Versions:"));
@@ -15413,7 +15617,8 @@ program2.command("init").description("Install Taiwan Invoice skill to current pr
15413
15617
  await initCommand({
15414
15618
  ai: options.ai,
15415
15619
  force: options.force,
15416
- global: options.global
15620
+ global: options.global,
15621
+ offline: options.offline
15417
15622
  });
15418
15623
  });
15419
15624
  program2.command("list").description("List supported AI platforms").action(listCommand);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "taiwan-invoice-skill",
3
- "version": "2.0.0",
3
+ "version": "2.1.0",
4
4
  "description": "CLI to install Taiwan E-Invoice skill for AI coding assistants",
5
5
  "bin": {
6
6
  "taiwan-invoice": "./dist/index.js"
@@ -10,7 +10,8 @@
10
10
  "assets"
11
11
  ],
12
12
  "scripts": {
13
- "build": "node scripts/build.js"
13
+ "build": "node scripts/build.js",
14
+ "prepublishOnly": "npm run build"
14
15
  },
15
16
  "keywords": [
16
17
  "taiwan",