xero-cli-bin 1.7.3 → 1.7.5

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/bin/LICENSE ADDED
@@ -0,0 +1,201 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship, whether in Source or
36
+ Object form, made available under the License, as indicated by a
37
+ copyright notice that is included in or attached to the work
38
+ (an example is provided in the Appendix below).
39
+
40
+ "Derivative Works" shall mean any work, whether in Source or Object
41
+ form, that is based on (or derived from) the Work and for which the
42
+ editorial revisions, annotations, elaborations, or other modifications
43
+ represent, as a whole, an original work of authorship. For the purposes
44
+ of this License, Derivative Works shall not include works that remain
45
+ separable from, or merely link (or bind by name) to the interfaces of,
46
+ the Work and Derivative Works thereof.
47
+
48
+ "Contribution" shall mean any work of authorship, including
49
+ the original version of the Work and any modifications or additions
50
+ to that Work or Derivative Works thereof, that is intentionally
51
+ submitted to Licensor for inclusion in the Work by the copyright owner
52
+ or by an individual or Legal Entity authorized to submit on behalf of
53
+ the copyright owner. For the purposes of this definition, "submitted"
54
+ means any form of electronic, verbal, or written communication sent
55
+ to the Licensor or its representatives, including but not limited to
56
+ communication on electronic mailing lists, source code control systems,
57
+ and issue tracking systems that are managed by, or on behalf of, the
58
+ Licensor for the purpose of discussing and improving the Work, but
59
+ excluding communication that is conspicuously marked or otherwise
60
+ designated in writing by the copyright owner as "Not a Contribution."
61
+
62
+ "Contributor" shall mean Licensor and any individual or Legal Entity
63
+ on behalf of whom a Contribution has been received by Licensor and
64
+ subsequently incorporated within the Work.
65
+
66
+ 2. Grant of Copyright License. Subject to the terms and conditions of
67
+ this License, each Contributor hereby grants to You a perpetual,
68
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
+ copyright license to reproduce, prepare Derivative Works of,
70
+ publicly display, publicly perform, sublicense, and distribute the
71
+ Work and such Derivative Works in Source or Object form.
72
+
73
+ 3. Grant of Patent License. Subject to the terms and conditions of
74
+ this License, each Contributor hereby grants to You a perpetual,
75
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
+ (except as stated in this section) patent license to make, have made,
77
+ use, offer to sell, sell, import, and otherwise transfer the Work,
78
+ where such license applies only to those patent claims licensable
79
+ by such Contributor that are necessarily infringed by their
80
+ Contribution(s) alone or by combination of their Contribution(s)
81
+ with the Work to which such Contribution(s) was submitted. If You
82
+ institute patent litigation against any entity (including a
83
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
84
+ or a Contribution incorporated within the Work constitutes direct
85
+ or contributory patent infringement, then any patent licenses
86
+ granted to You under this License for that Work shall terminate
87
+ as of the date such litigation is filed.
88
+
89
+ 4. Redistribution. You may reproduce and distribute copies of the
90
+ Work or Derivative Works thereof in any medium, with or without
91
+ modifications, and in Source or Object form, provided that You
92
+ meet the following conditions:
93
+
94
+ (a) You must give any other recipients of the Work or
95
+ Derivative Works a copy of this License; and
96
+
97
+ (b) You must cause any modified files to carry prominent notices
98
+ stating that You changed the files; and
99
+
100
+ (c) You must retain, in the Source form of any Derivative Works
101
+ that You distribute, all copyright, patent, trademark, and
102
+ attribution notices from the Source form of the Work,
103
+ excluding those notices that do not pertain to any part of
104
+ the Derivative Works; and
105
+
106
+ (d) If the Work includes a "NOTICE" text file as part of its
107
+ distribution, then any Derivative Works that You distribute must
108
+ include a readable copy of the attribution notices contained
109
+ within such NOTICE file, excluding those notices that do not
110
+ pertain to any part of the Derivative Works, in at least one
111
+ of the following places: within a NOTICE text file distributed
112
+ as part of the Derivative Works; within the Source form or
113
+ documentation, if provided along with the Derivative Works; or,
114
+ within a display generated by the Derivative Works, if and
115
+ wherever such third-party notices normally appear. The contents
116
+ of the NOTICE file are for informational purposes only and
117
+ do not modify the License. You may add Your own attribution
118
+ notices within Derivative Works that You distribute, alongside
119
+ or as an addendum to the NOTICE text from the Work, provided
120
+ that such additional attribution notices cannot be construed
121
+ as modifying the License.
122
+
123
+ You may add Your own copyright statement to Your modifications and
124
+ may provide additional or different license terms and conditions
125
+ for use, reproduction, or distribution of Your modifications, or
126
+ for any such Derivative Works as a whole, provided Your use,
127
+ reproduction, and distribution of the Work otherwise complies with
128
+ the conditions stated in this License.
129
+
130
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
131
+ any Contribution intentionally submitted for inclusion in the Work
132
+ by You to the Licensor shall be under the terms and conditions of
133
+ this License, without any additional terms or conditions.
134
+ Notwithstanding the above, nothing herein shall supersede or modify
135
+ the terms of any separate license agreement you may have executed
136
+ with Licensor regarding such Contributions.
137
+
138
+ 6. Trademarks. This License does not grant permission to use the trade
139
+ names, trademarks, service marks, or product names of the Licensor,
140
+ except as required for reasonable and customary use in describing the
141
+ origin of the Work and reproducing the content of the NOTICE file.
142
+
143
+ 7. Disclaimer of Warranty. Unless required by applicable law or
144
+ agreed to in writing, Licensor provides the Work (and each
145
+ Contributor provides its Contributions) on an "AS IS" BASIS,
146
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
+ implied, including, without limitation, any warranties or conditions
148
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
+ PARTICULAR PURPOSE. You are solely responsible for determining the
150
+ appropriateness of using or redistributing the Work and assume any
151
+ risks associated with Your exercise of permissions under this License.
152
+
153
+ 8. Limitation of Liability. In no event and under no legal theory,
154
+ whether in tort (including negligence), contract, or otherwise,
155
+ unless required by applicable law (such as deliberate and grossly
156
+ negligent acts) or agreed to in writing, shall any Contributor be
157
+ liable to You for damages, including any direct, indirect, special,
158
+ incidental, or consequential damages of any character arising as a
159
+ result of this License or out of the use or inability to use the
160
+ Work (including but not limited to damages for loss of goodwill,
161
+ work stoppage, computer failure or malfunction, or any and all
162
+ other commercial damages or losses), even if such Contributor
163
+ has been advised of the possibility of such damages.
164
+
165
+ 9. Accepting Warranty or Additional Liability. While redistributing
166
+ the Work or Derivative Works thereof, You may choose to offer,
167
+ and charge a fee for, acceptance of support, warranty, indemnity,
168
+ or other liability obligations and/or rights consistent with this
169
+ License. However, in accepting such obligations, You may act only
170
+ on Your own behalf and on Your sole responsibility, not on behalf
171
+ of any other Contributor, and only if You agree to indemnify,
172
+ defend, and hold each Contributor harmless for any liability
173
+ incurred by, or claims asserted against, such Contributor by reason
174
+ of your accepting any such warranty or additional liability.
175
+
176
+ END OF TERMS AND CONDITIONS
177
+
178
+ APPENDIX: How to apply the Apache License to your work.
179
+
180
+ To apply the Apache License to your work, attach the following
181
+ boilerplate notice, with the fields enclosed by brackets "[]"
182
+ replaced with your own identifying information. (Don't include
183
+ the brackets!) The text should be enclosed in the appropriate
184
+ comment syntax for the file format. We also recommend that a
185
+ file or class name and description of purpose be included on the
186
+ same "printed page" as the copyright notice for easier
187
+ identification within third-party archives.
188
+
189
+ Copyright [yyyy] [name of copyright owner]
190
+
191
+ Licensed under the Apache License, Version 2.0 (the "License");
192
+ you may not use this file except in compliance with the License.
193
+ You may obtain a copy of the License at
194
+
195
+ http://www.apache.org/licenses/LICENSE-2.0
196
+
197
+ Unless required by applicable law or agreed to in writing, software
198
+ distributed under the License is distributed on an "AS IS" BASIS,
199
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200
+ See the License for the specific language governing permissions and
201
+ limitations under the License.
package/bin/README.md ADDED
@@ -0,0 +1,666 @@
1
+ # Xero CLI
2
+
3
+ [![Go Version](https://img.shields.io/go.mod/1.21)](https://golang.org/)
4
+ [![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](LICENSE)
5
+ [![Release](https://img.shields.io/github/v/release/MMHK/xero-cli)](https://github.com/MMHK/xero-cli/releases)
6
+
7
+ Xero Accounting API 的命令行工具,使用 OAuth2 PKCE 流程進行認證。
8
+
9
+ ## 功能特性
10
+
11
+ - ✅ OAuth2 PKCE 認證流程(適合 CLI/桌面應用)
12
+ - ✅ **Config 配置管理系統**(獨立的 config 命令)
13
+ - ✅ 支援 Refresh Token 離線訪問(60 天)
14
+ - ✅ AES-256-GCM 加密儲存 Token 和 Config(機器綁定)
15
+ - ✅ 扁平化專案結構,易於理解和維護
16
+ - ✅ 多種查詢功能:發票、聯絡人、帳戶、付款、貸項通知單
17
+ - ✅ 可作為 AI Agent Skill 整合到自動化流程
18
+
19
+ ## 快速開始
20
+
21
+ ### 安裝方式
22
+
23
+ #### 方法一:下載預編譯 Binary(推薦)
24
+
25
+ 從 [GitHub Releases](https://github.com/MMHK/xero-cli/releases) 下載適合您系統的版本:
26
+
27
+ | 平台 | 架構 | 下載 |
28
+ |------|------|------|
29
+ | Windows | x86_64 (amd64) | `xero-cli_Windows_x86_64.zip` |
30
+ | Windows | arm64 | `xero-cli_Windows_arm64.zip` |
31
+ | macOS | x86_64 (Intel) | `xero-cli_Darwin_x86_64.tar.gz` |
32
+ | macOS | arm64 (M1/M2/M3) | `xero-cli_Darwin_arm64.tar.gz` |
33
+ | Linux | x86_64 (amd64) | `xero-cli_Linux_x86_64.tar.gz` |
34
+ | Linux | arm64 | `xero-cli_Linux_arm64.tar.gz` |
35
+
36
+ **安裝步驟:**
37
+
38
+ ```bash
39
+ # macOS/Linux
40
+ tar -xzf xero-cli_<OS>_<ARCH>.tar.gz
41
+ chmod +x xero-cli
42
+ sudo mv xero-cli /usr/local/bin/
43
+
44
+ # Windows (PowerShell)
45
+ Expand-Archive xero-cli_Windows_x86_64.zip -DestinationPath C:\Program Files\xero-cli
46
+ # 將 C:\Program Files\xero-cli 加入 PATH
47
+ ```
48
+
49
+ **驗證安裝:**
50
+
51
+ ```bash
52
+ # 檢查校驗和
53
+ sha256sum -c checksums.txt
54
+
55
+ # 檢查版本
56
+ ./xero-cli --version
57
+ ./xero-cli -V
58
+ ```
59
+
60
+ #### 方法二:從原始碼編譯
61
+
62
+ ```bash
63
+ git clone https://github.com/MMHK/xero-cli.git
64
+ cd xero-cli
65
+ go build -o xero-cli.exe
66
+ ```
67
+
68
+ ### 2. 設定
69
+
70
+ #### 方法一:使用 Config 命令(推薦)
71
+
72
+ ```bash
73
+ # 初始化配置(交互式)
74
+ xero-cli config --init
75
+
76
+ # 查看配置
77
+ xero-cli config
78
+
79
+ # 更新配置
80
+ xero-cli config --update
81
+
82
+ # 重置配置
83
+ xero-cli config --reset
84
+ ```
85
+
86
+ **配置儲存位置**:
87
+ - Windows: `C:\Users\<user>\AppData\Roaming\xero-cli\config.json`
88
+ - macOS: `/Users/<user>/Library/Application Support/xero-cli/config.json`
89
+ - Linux: `/home/<user>/.config/xero-cli/config.json`
90
+
91
+ **安全特性**:
92
+ - AES-256-GCM 加密儲存
93
+ - 機器綁定(防止跨機器使用)
94
+ - 文件權限 0600(僅所有者可讀寫)
95
+
96
+ #### 方法二:使用 .env 文件
97
+
98
+ 建立 `.env` 檔案:
99
+
100
+ ```env
101
+ XERO_CLIENT_ID=your_client_id_here
102
+ XERO_CLIENT_SECRET=your_client_secret_here # PKCE 可選,一般 OAuth 必需
103
+ XERO_REDIRECT_URI=http://localhost:3456/callback
104
+ XERO_SCOPES=openid profile email accounting.transactions accounting.settings offline_access
105
+ ```
106
+
107
+ **預設 Scopes**:
108
+ ```
109
+ openid profile email accounting.transactions accounting.settings accounting.contacts offline_access
110
+ ```
111
+
112
+ **配置來源優先級**:
113
+ 1. CLI flags (`--client-id`, `--secret`, ...) - 最高優先級
114
+ 2. 環境變數 (`.env`) - 中優先級
115
+ 3. 加密 config.json - 低優先級
116
+ 4. 預設值 - 最低優先級
117
+
118
+ ### 3. 使用
119
+
120
+ ```bash
121
+ # 認證(使用保存的配置)
122
+ ./xero-cli auth
123
+
124
+ # 強制重新認證
125
+ ./xero-cli auth --force
126
+
127
+ # 切換 Tenant/Organization
128
+ ./xero-cli auth --switch
129
+
130
+ # 檢查狀態
131
+ ./xero-cli status
132
+
133
+ # 查詢發票
134
+ ./xero-cli invoices list --type ACCREC --status AUTHORISED
135
+
136
+ # 查詢聯絡人
137
+ ./xero-cli contacts list --type customer
138
+
139
+ # 搜尋發票(使用 SearchTerm)
140
+ ./xero-cli invoices list --search-term "INV-2024"
141
+
142
+ # 搜尋聯絡人(使用 SearchTerm)
143
+ ./xero-cli contacts list --search-term "Smith"
144
+
145
+ # 查詢貸項通知單
146
+ ./xero-cli creditnotes list --type ACCREC --status AUTHORISED
147
+
148
+ # 查詢剩餘可沖銷金額 > 0 的貸項通知單
149
+ ./xero-cli creditnotes list --where "RemainingCredit>0"
150
+
151
+ # JSON 輸出
152
+ ./xero-cli invoices list --json
153
+
154
+ # 詳細模式
155
+ ./xero-cli status -v
156
+ ```
157
+
158
+ ## 命令參考
159
+
160
+ | 命令 | 用途 | 範例 |
161
+ |------|------|------|
162
+ | `auth` | 啟動認證 | `xero-cli auth` |
163
+ | `auth --force` | 強制重新認證 | `xero-cli auth --force` |
164
+ | `auth --switch` | 切換 Tenant | `xero-cli auth --switch` |
165
+ | `config` | 配置管理 | `xero-cli config` |
166
+ | `config --init` | 初始化配置 | `xero-cli config --init` |
167
+ | `config --update` | 更新配置 | `xero-cli config --update` |
168
+ | `config --reset` | 重置配置 | `xero-cli config --reset` |
169
+ | `status` | 檢查狀態 | `xero-cli status` |
170
+ | `refresh` | 刷新 Token | `xero-cli refresh` |
171
+ | `revoke` | 撤銷授權 | `xero-cli revoke` |
172
+ | `connections` | 列出組織 | `xero-cli connections` |
173
+ | `invoices list` | 發票列表 | `xero-cli invoices list --type ACCREC` |
174
+ | `invoices get` | 單一發票 | `xero-cli invoices get <uuid>` |
175
+ | `contacts list` | 聯絡人列表 | `xero-cli contacts list --type customer` |
176
+ | `contacts get` | 單一聯絡人 | `xero-cli contacts get <uuid>` |
177
+ | `accounts list` | 科目列表 | `xero-cli accounts list --type BANK` |
178
+ | `accounts get` | 單一科目 | `xero-cli accounts get <code>` |
179
+ | `payments list` | 付款列表 | `xero-cli payments list --type AR` |
180
+ | `payments get` | 單一付款 | `xero-cli payments get <uuid>` |
181
+ | `creditnotes list` | 貸項通知單列表 | `xero-cli creditnotes list --type ACCREC` |
182
+ | `creditnotes get` | 單一貸項通知單 | `xero-cli creditnotes get <uuid>` |
183
+
184
+ ### 通用篩選參數
185
+
186
+ | 參數 | 說明 | 預設 | 範圍 |
187
+ |------|------|------|------|
188
+ | `--page` | 頁碼 | 1 | 1-N |
189
+ | `--page-size` | 每頁數量 | 50 | 1-100 |
190
+ | `--order-by` | 排序欄位 | varies | 任意欄位名稱 |
191
+ | `--sort-direction` | 排序方向 | varies | ASC/DESC |
192
+ | `--where` | WHERE 條件 | - | Xero 語法 |
193
+ | `--search-term` | 搜尋關鍵字 | - | 文字搜尋 |
194
+ | `--json` | JSON 輸出 | false | - |
195
+
196
+ ### SearchTerm 搜尋功能
197
+
198
+ `--search-term` 參數提供快速文字搜尋功能,適用於以下場景:
199
+
200
+ **Invoices(發票搜尋)**:
201
+ ```bash
202
+ # 搜尋發票號碼或參考號
203
+ xero-cli invoices list --search-term "INV-2024"
204
+
205
+ # 搜尋參考號包含 "REF123" 的應收發票
206
+ xero-cli invoices list --search-term "REF123" --type ACCREC
207
+
208
+ # 結合其他篩選條件
209
+ xero-cli invoices list --search-term "INV" --status AUTHORISED --page-size 20
210
+ ```
211
+
212
+ 搜尋範圍:`InvoiceNumber`, `Reference`(不區分大小寫)
213
+
214
+ **Contacts(聯絡人搜尋)**:
215
+ ```bash
216
+ # 搜尋聯絡人名稱、郵件等
217
+ xero-cli contacts list --search-term "Smith"
218
+
219
+ # 搜尋客戶且名稱包含 "john"
220
+ xero-cli contacts list --search-term "john" --type customer
221
+
222
+ # 結合排序
223
+ xero-cli contacts list --search-term "ABC" --order-by Name --sort-direction ASC
224
+ ```
225
+
226
+ 搜尋範圍:`Name`, `FirstName`, `LastName`, `ContactNumber`, `CompanyNumber`, `EmailAddress`(不區分大小寫)
227
+
228
+ **與 WHERE 的差異**:
229
+ - `--search-term`:快速全文搜尋,Xero API 內部優化,效能佳
230
+ - `--where`:靈活的條件組合,支持複雜邏輯運算
231
+
232
+ 建議優先使用 `--search-term` 進行簡單文字搜尋,複雜條件再使用 `--where`。
233
+
234
+ ### Order By 範例
235
+
236
+ ```bash
237
+ # 依日期倒序(預設)
238
+ xero-cli invoices list --order-by Date --sort-direction DESC
239
+
240
+ # 依金額倒序(大額在前)
241
+ xero-cli invoices list --order-by Total --sort-direction DESC
242
+
243
+ # 依名稱正序(A-Z)
244
+ xero-cli contacts list --order-by Name --sort-direction ASC
245
+
246
+ # 依聯絡人名稱排序
247
+ xero-cli invoices list --order-by Contact.Name --sort-direction ASC
248
+
249
+ # 依剩餘可沖銷金額排序(貸項通知單)
250
+ xero-cli creditnotes list --order-by RemainingCredit --sort-direction DESC
251
+
252
+ # 結合 SearchTerm 搜尋
253
+ xero-cli invoices list --search-term "INV" --order-by Date --sort-direction DESC
254
+ xero-cli contacts list --search-term "ABC" --order-by Name --sort-direction ASC
255
+ ```
256
+
257
+ **Xero API 優化排序欄位**:
258
+ - **Invoices**: `InvoiceId`, `UpdatedDateUTC`, `Date`(預設:UpdatedDateUTC ASC, InvoiceId ASC)
259
+ - **Contacts**: `UpdatedDateUTC`, `ContactId`(預設:UpdatedDateUTC ASC, ContactId ASC)
260
+ - **Accounts**: `Code`(預設:Code ASC)
261
+ - **Payments**: `UpdatedDateUTC`, `Date`, `PaymentId`(預設:UpdatedDateUTC ASC, PaymentId ASC)
262
+ - **CreditNotes**: `UpdatedDateUTC`, `CreditNoteId`(預設:UpdatedDateUTC ASC, CreditNoteId ASC)
263
+
264
+ ### WHERE 查詢範例
265
+
266
+ ```bash
267
+ # 未結清應收發票
268
+ --where "Type=='ACCREC'&&AmountDue>0"
269
+
270
+ # 逾期發票
271
+ --where "DueDate<DateTime.Today&&AmountDue>0"
272
+
273
+ # 日期範圍
274
+ --where "Date>=DateTime(2024, 01, 01) AND Date<DateTime(2024, 02, 01)"
275
+
276
+ # 指定客戶
277
+ --where "Contact.ContactID=Guid('uuid-here')"
278
+
279
+ # 金額範圍
280
+ --where "AmountDue>=5000 AND AmountDue<6000"
281
+
282
+ # 貸項通知單查詢
283
+ # 剩餘可沖銷金額 > 0
284
+ --where "RemainingCredit>0"
285
+
286
+ # 已授權的應收貸項通知單
287
+ --where "Type=='ACCREC' && Status=='AUTHORISED'"
288
+
289
+ # 依金額排序
290
+ --order-by Total --sort-direction DESC
291
+
292
+ # 文字字段部分匹配(Contacts)
293
+ # 名稱包含 "MOTOR"
294
+ --where "Name.Contains('MOTOR')"
295
+
296
+ # 名稱以 "ABC" 開頭
297
+ --where "Name.StartsWith('ABC')"
298
+
299
+ # 名稱以 "LIMITED" 結尾
300
+ --where "Name.EndsWith('LIMITED')"
301
+
302
+ # 郵箱包含 "gmail"
303
+ --where "EmailAddress.Contains('gmail')"
304
+
305
+ # 統一編號包含 "123"
306
+ --where "TaxNumber.Contains('123')"
307
+
308
+ # 地址包含 "Road"
309
+ --where "AddressLine1.Contains('Road')"
310
+
311
+ # 城市包含 "Taipei"
312
+ --where "City.Contains('Taipei')"
313
+
314
+ # 聯絡人編號包含 "CUST"
315
+ --where "AccountNumber.Contains('CUST')"
316
+
317
+ # 組合查詢:客戶且名稱包含 "LIMITED"
318
+ --where "IsCustomer==true && Name.Contains('LIMITED')"
319
+
320
+ # 文字字段部分匹配(Invoices)
321
+ # 參考號包含 "INV"
322
+ --where "Reference.Contains('INV')"
323
+
324
+ # 發票號以 "2024" 開頭
325
+ --where "InvoiceNumber.StartsWith('2024')"
326
+
327
+ # 文字字段部分匹配(Accounts)
328
+ # 科目名稱包含 "Bank"
329
+ --where "Name.Contains('Bank')"
330
+
331
+ # 科目代碼以 "1" 開頭
332
+ --where "Code.StartsWith('1')"
333
+
334
+ # 文字字段部分匹配(Payments)
335
+ # 付款參考號包含 "PAY"
336
+ --where "Reference.Contains('PAY')"
337
+
338
+ # 文字字段部分匹配(CreditNotes)
339
+ # 參考號包含 "CN"
340
+ --where "Reference.Contains('CN')"
341
+
342
+ # 貸項單號以 "2024" 開頭
343
+ --where "CreditNoteNumber.StartsWith('2024')"
344
+
345
+ # SearchTerm vs WHERE 使用建議
346
+ # 簡單文字搜尋(推薦使用 searchTerm,效能更佳)
347
+ xero-cli invoices list --search-term "INV-2024"
348
+ xero-cli contacts list --search-term "Smith"
349
+
350
+ # 複雜條件組合(使用 where)
351
+ xero-cli invoices list --search-term "INV" --where "AmountDue>0"
352
+ ```
353
+
354
+ ### 測試
355
+
356
+ 詳細測試文檔請參閱 [測試指南](./docs/guides/testing.md)。
357
+
358
+ ```bash
359
+ # 運行所有測試
360
+ go test ./...
361
+
362
+ # 詳細輸出
363
+ go test ./... -v
364
+
365
+ # 覆蓋率報告
366
+ go test ./... -cover
367
+
368
+ # 單一測試
369
+ go test -run ^TestGetPayment_Mock$ ./...
370
+ go test -run ^TestBuildOrderClause$ ./...
371
+ go test -run ^TestBuildCreditNoteWhereClause$ ./...
372
+ ```
373
+
374
+ **測試涵蓋範圍**:70+ 測試用例(API 測試、WHERE Clause 測試、排序測試、認證測試)
375
+
376
+ [查看完整測試指南 →](./docs/guides/testing.md)
377
+
378
+ #### 代碼質量檢查
379
+
380
+ ```bash
381
+ go fmt ./... # 格式化
382
+ go vet ./... # 靜態分析
383
+ go build -o xero-cli.exe # 編譯
384
+ ```
385
+
386
+ **測試檔案**:`api_payments_test.go`, `api_creditnotes_test.go`, `cmd_helpers_test.go`, `api_test.go`, `auth_test.go`, `config_test.go`
387
+
388
+ [查看完整測試指南 →](./docs/guides/testing.md)
389
+
390
+ ## 專案結構
391
+
392
+ ```
393
+ .
394
+ ├── main.go # 程式入口
395
+ ├── types.go # 資料結構定義
396
+ ├── auth.go # OAuth2 PKCE 認證邏輯
397
+ ├── api.go # Xero API 呼叫封裝
398
+ ├── api_*.go # 各類 API 查詢實作
399
+ ├── config.go # 設定與環境變數 + Config 管理
400
+ ├── config_action.go # Config action 實現
401
+ ├── cmd.go # CLI 命令定義
402
+ ├── cmd_helpers.go # 命令輔助函數
403
+ ├── crypto.go # 加密工具
404
+ ├── utils.go # 工具函數
405
+ ├── go.mod
406
+ ├── README.md # 主說明文件
407
+ ├── AGENTS.md # AI 開發指導原則
408
+ ├── .env.example # 環境變數範本
409
+ └── docs/ # 文檔目錄
410
+ ├── README.md # 開發指南索引
411
+ ├── api/ # API 端點文檔
412
+ │ ├── invoices.md
413
+ │ ├── contacts.md
414
+ │ ├── payments.md
415
+ │ ├── accounts.md
416
+ │ └── credit-notes.md
417
+ └── guides/ # 實現指南
418
+ ├── oauth2-pkce.md
419
+ ├── error-handling.md
420
+ ├── config-system.md
421
+ ├── testing.md
422
+ ├── ai-agent-integration.md
423
+ └── business-scenarios.md
424
+ ```
425
+
426
+ ## 開發命令
427
+
428
+ ```bash
429
+ # 編譯
430
+ go build -o xero-cli.exe
431
+
432
+ # 執行
433
+ go run main.go
434
+
435
+ # 格式化
436
+ go fmt ./...
437
+
438
+ # Lint
439
+ golint ./...
440
+
441
+ # 靜態分析
442
+ go vet ./...
443
+
444
+ # 測試
445
+ go test ./...
446
+ go test -run ^TestName$ ./...
447
+ go test -cover ./...
448
+ ```
449
+
450
+ ## OAuth2 PKCE 流程
451
+
452
+ ```
453
+ 1. 生成 code_verifier (43-128 字元)
454
+ 2. 計算 code_challenge = SHA256(verifier)
455
+ 3. 開啟瀏覽器到授權網址
456
+ 4. localhost:3456 監聽回調接收 auth_code
457
+ 5. 用 auth_code + code_verifier 交換 token
458
+ 6. 取得 access_token (30 分鐘) + refresh_token (60 天)
459
+ 7. 使用 access_token 呼叫 API
460
+ ```
461
+
462
+ **授權網址**:
463
+ ```
464
+ https://login.xero.com/identity/connect/authorize?
465
+ response_type=code&
466
+ client_id=YOUR_CLIENT_ID&
467
+ redirect_uri=http://localhost:3456/callback&
468
+ scope=openid%20profile%20email%20accounting.transactions%20offline_access&
469
+ state=random_state&
470
+ code_challenge=CHALLENGE&
471
+ code_challenge_method=S256
472
+ ```
473
+
474
+ **Token 端點**:
475
+ ```
476
+ POST https://identity.xero.com/connect/token
477
+ ```
478
+
479
+ ## Token 管理
480
+
481
+ | Token 類型 | 過期時間 |
482
+ |------------|----------|
483
+ | Access Token | 30 分鐘 |
484
+ | Refresh Token | 60 天 |
485
+
486
+ **儲存路徑**:
487
+ - Windows: `C:\Users\<user>\AppData\Roaming\xero-cli\tokens.json`
488
+ - macOS: `/Users/<user>/Library/Application Support/xero-cli/tokens.json`
489
+ - Linux: `/home/<user>/.config/xero-cli/tokens.json`
490
+
491
+ **Config 儲存路徑**:
492
+ - Windows: `C:\Users\<user>\AppData\Roaming\xero-cli\config.json`
493
+ - macOS: `/Users/<user>/Library/Application Support/xero-cli/config.json`
494
+ - Linux: `/home/<user>/.config/xero-cli/config.json`
495
+
496
+ **加密方式**: AES-256-GCM 加密,使用機器特徵生成密鑰(綁定當前機器)
497
+
498
+ **安全特性**:
499
+ - AES-256-GCM Authenticated Encryption
500
+ - scrypt KDF 密鑰派生 (N=32768, r=8, p=1)
501
+ - 機器綁定(machineid.ID())
502
+ - 平台驗證(防止跨機器使用)
503
+ - 文件權限 0600(僅所有者可讀寫)
504
+
505
+ ## 常用 Scopes
506
+
507
+ | Scope | 說明 |
508
+ |-------|------|
509
+ | `openid profile email` | OpenID Connect 用戶資訊 |
510
+ | `accounting.transactions` | 讀取發票、帳單、付款、**貸項通知單**等交易資料 |
511
+ | `accounting.settings` | 讀取組織設定、科目表等基本設定資訊 |
512
+ | `accounting.contacts` | 讀取客戶、供應商聯絡人資訊 |
513
+ | `offline_access` | **必需** 取得 Refresh Token 以支持離線訪問 |
514
+
515
+ ## 安全注意事項
516
+
517
+ 1. **勿提交機密資訊**: `.env`、`config.json` 和 `token` 檔案必須加入 `.gitignore`
518
+ 2. **加密儲存**: Token 和 Config 使用 AES-256-GCM 加密,綁定當前機器
519
+ 3. **檔案權限**: Token 和 Config 檔案使用 0600 權限(僅所有者可讀寫)
520
+ 4. **定期撤銷**: 不再使用時執行 `./xero-cli revoke`
521
+ 5. **最小權限**: 只申請必要的 scopes
522
+ 6. **機器綁定**: Config 和 Token 無法在不同機器間遷移(安全特性)
523
+ 7. **密碼模式輸入**: Client Secret 使用隱藏輸入(不回顯)
524
+
525
+ ## API 基礎
526
+
527
+ **Base URL**:
528
+ ```
529
+ https://api.xero.com/api.xro/2.0/
530
+ ```
531
+
532
+ **Headers**:
533
+ ```
534
+ Authorization: Bearer <access_token>
535
+ Xero-tenant-id: <tenant_id>
536
+ Accept: application/json
537
+ ```
538
+
539
+ **Rate Limits**:
540
+ - 每分鐘:60 次
541
+ - 每小時:3600 次
542
+ - 每日:50000 次
543
+
544
+ ## 錯誤處理
545
+
546
+ | 錯誤 | 原因 | 解決方法 |
547
+ |------|------|----------|
548
+ | `Not authenticated` | 未執行 auth 命令 | 執行 `xero-cli auth` |
549
+ | `Token expired` | Access token 已過期 | 執行 `xero-cli refresh` |
550
+ | `No connections found` | 無連接的組織 | 檢查 Xero 組織設定 |
551
+ | `Rate limit exceeded` | 超過 API 限制 | 等待後重試 |
552
+
553
+ ## AI Agent Skill 整合
554
+
555
+ Xero CLI 可作為 AI Agent(opencode、Cline、Cursor 等)的 CLI Skill。
556
+
557
+ **快速範例**:
558
+
559
+ ```bash
560
+ # AI 查詢發票
561
+ xero-cli invoices list --type ACCREC --status AUTHORISED --json
562
+
563
+ # AI 查詢客戶
564
+ xero-cli contacts list --type customer --json
565
+ ```
566
+
567
+ [查看完整 AI Agent 整合指南 →](./docs/guides/ai-agent-integration.md)
568
+
569
+ ## 業務場景範例
570
+
571
+ 完整的業務場景範例(財務報表、往來對象查詢、進階查詢、jq 整合、貸項通知單應用)請參閱:
572
+
573
+ [查看業務場景範例 →](./docs/guides/business-scenarios.md)
574
+
575
+ ### 快速範例
576
+
577
+ ```bash
578
+ # 逾期發票查詢
579
+ xero-cli invoices list --where "Type==\"ACCREC\" && AmountDue>0 && DueDate<DateTime.Today"
580
+
581
+ # 本月收款總額
582
+ xero-cli payments list --type AR --date-from 2024-02-01 --date-to 2024-02-29 --json | jq '[.[].Amount] | add'
583
+
584
+ # 貸項通知單(剩餘可沖銷金額>0)
585
+ xero-cli creditnotes list --where "RemainingCredit>0" --order-by RemainingCredit --sort-direction DESC
586
+ ```
587
+
588
+ ## 自動打包與 Release
589
+
590
+ 本專案使用 GoReleaser 和 GitHub Actions 實現自動化多平台打包。
591
+
592
+ ### 支援的平台
593
+
594
+ | 平台 | 架構 | 檔案格式 |
595
+ |------|------|----------|
596
+ | Windows | x86_64, arm64 | `.zip` |
597
+ | macOS | x86_64 (Intel), arm64 (M1/M2/M3) | `.tar.gz` |
598
+ | Linux | x86_64, arm64 | `.tar.gz` |
599
+
600
+ ### 建立 Release
601
+
602
+ ```bash
603
+ # 1. 建立語義化版本標籤
604
+ git tag v1.0.0
605
+
606
+ # 2. Push 標籤到 GitHub(自動觸發打包)
607
+ git push origin v1.0.0
608
+
609
+ # 3. 前往 GitHub Actions 查看進度
610
+ # https://github.com/MMHK/xero-cli/actions
611
+ ```
612
+
613
+ ### 本地測試編譯
614
+
615
+ ```bash
616
+ # 安裝 GoReleaser
617
+ go install github.com/goreleaser/goreleaser/v2@latest
618
+
619
+ # 測試編譯(不建立 release)
620
+ goreleaser build --snapshot --clean
621
+
622
+ # 或使用提供的腳本
623
+ ./scripts/build-release.sh # macOS/Linux
624
+ .\scripts\build-release.bat # Windows
625
+ ```
626
+
627
+ ### 配置檔案
628
+
629
+ - `.goreleaser.yaml` - GoReleaser 配置
630
+ - `.github/workflows/release.yml` - GitHub Actions 配置
631
+
632
+ ### 編譯產出
633
+
634
+ 每次 release 會自動生成:
635
+
636
+ - 6 個平台的 binary(Windows/macOS/Linux × amd64/arm64)
637
+ - `checksums.txt` - SHA256 校驗和
638
+ - 自動生成的 CHANGELOG
639
+
640
+ ### Release 前檢查清單
641
+
642
+ - [ ] 所有測試通過:`go test ./...`
643
+ - [ ] 代碼格式化:`go fmt ./...`
644
+ - [ ] 靜態分析:`go vet ./...`
645
+ - [ ] 本地測試編譯:`goreleaser build --snapshot`
646
+
647
+ ## 開發階段
648
+
649
+ - [x] 第一階段:核心認證功能
650
+ - [x] 第二階段:API 查詢功能
651
+ - [x] 第三階段:CLI 命令整合
652
+ - [x] 第四階段:測試與文件
653
+
654
+ ## 相關資源
655
+
656
+ - [Xero Developer Portal](https://developer.xero.com/app/manage)
657
+ - [OAuth2 PKCE 文檔](https://developer.xero.com/documentation/guides/oauth2/pkce-flow)
658
+ - [Accounting API](https://developer.xero.com/documentation/api/accounting)
659
+ - [Go OAuth2 套件](https://pkg.go.dev/golang.org/x/oauth2)
660
+ - [GoReleaser 官方文檔](https://goreleaser.com/)
661
+ - [GoReleaser v2 遷移指南](https://goreleaser.com/blog/goreleaser-v2/)
662
+ - [GitHub Actions 文檔](https://docs.github.com/en/actions)
663
+
664
+ ## 授權
665
+
666
+ MIT License
package/bin/xero-cli ADDED
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env node
2
+
3
+ const { spawn } = require('child_process');
4
+ const { join } = require('path');
5
+ const { platform } = process;
6
+
7
+ const ext = platform === 'win32' ? '.exe' : '';
8
+ const binaryPath = join(__dirname, `xero-cli${ext}`);
9
+
10
+ spawn(binaryPath, process.argv.slice(2), { stdio: 'inherit' })
11
+ .on('error', (err) => {
12
+ console.error('Failed to start xero-cli:', err.message);
13
+ process.exit(1);
14
+ })
15
+ .on('close', (code) => {
16
+ process.exit(code);
17
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xero-cli-bin",
3
- "version": "1.7.3",
3
+ "version": "1.7.5",
4
4
  "description": "Xero Accounting API CLI - Xero 會計 API 命令行工具",
5
5
  "bin": {
6
6
  "xero-cli": "./bin/xero-cli"
@@ -28,6 +28,24 @@ function getFileName() {
28
28
  return platform === 'win32' ? 'xero-cli.exe' : 'xero-cli';
29
29
  }
30
30
 
31
+ async function deleteWithRetry(filePath, maxRetries = 3) {
32
+ for (let i = 0; i < maxRetries; i++) {
33
+ try {
34
+ if (platform === 'win32') {
35
+ fs.rmSync(filePath, { force: true, recursive: true });
36
+ } else {
37
+ fs.unlinkSync(filePath);
38
+ }
39
+ return;
40
+ } catch (error) {
41
+ if (i === maxRetries - 1) {
42
+ throw error;
43
+ }
44
+ await new Promise(resolve => setTimeout(resolve, 500 * (i + 1)));
45
+ }
46
+ }
47
+ }
48
+
31
49
  async function downloadFromGitHubRelease() {
32
50
  const pkg = require('../package.json');
33
51
  const version = pkg.version.replace(/^v/, '');
@@ -105,78 +123,6 @@ async function downloadFromGitHubRelease() {
105
123
  }
106
124
  }
107
125
 
108
- async function deleteWithRetry(filePath, maxRetries = 3) {
109
- for (let i = 0; i < maxRetries; i++) {
110
- try {
111
- if (platform === 'win32') {
112
- fs.rmSync(filePath, { force: true, recursive: true });
113
- } else {
114
- fs.unlinkSync(filePath);
115
- }
116
- return;
117
- } catch (error) {
118
- if (i === maxRetries - 1) {
119
- throw error;
120
- }
121
- await new Promise(resolve => setTimeout(resolve, 500 * (i + 1)));
122
- }
123
- }
124
- }
125
- });
126
-
127
- dl.on('progress', (stats) => {
128
- const percent = stats.progress.toFixed(1);
129
- const downloaded = (stats.downloaded / 1024 / 1024).toFixed(2);
130
- const total = (stats.total / 1024 / 1024).toFixed(2);
131
- process.stdout.write(`[xero-cli-bin] Downloading: ${percent}% (${downloaded}/${total} MB)\r`);
132
- });
133
-
134
- dl.on('end', () => {
135
- console.log('\n[xero-cli-bin] Download completed');
136
- resolve();
137
- });
138
-
139
- dl.on('error', (err) => {
140
- reject(err);
141
- });
142
-
143
- dl.start();
144
- });
145
-
146
- console.log('[xero-cli-bin] Extracting...');
147
-
148
- if (!fs.existsSync(extractDir)) {
149
- fs.mkdirSync(extractDir, { recursive: true });
150
- }
151
-
152
- if (platform === 'win32') {
153
- await extractZip(downloadPath, { dir: extractDir });
154
- } else {
155
- await tar.x({
156
- file: downloadPath,
157
- cwd: extractDir,
158
- strip: 0
159
- });
160
- }
161
-
162
- fs.unlinkSync(downloadPath);
163
-
164
- const binaryPath = join(extractDir, getFileName());
165
-
166
- if (platform !== 'win32') {
167
- fs.chmodSync(binaryPath, 0755);
168
- }
169
-
170
- console.log('[xero-cli-bin] Installation complete!');
171
- console.log(`[xero-cli-bin] Binary installed to: ${binaryPath}`);
172
- } catch (error) {
173
- if (fs.existsSync(downloadPath)) {
174
- fs.unlinkSync(downloadPath);
175
- }
176
- throw error;
177
- }
178
- }
179
-
180
126
  console.log(`[xero-cli-bin] Platform: ${platform} ${arch}`);
181
127
  console.log(`[xero-cli-bin] Node.js: ${process.version}`);
182
128