@dac-tech-team-tw/itsaplan-cli 0.0.0-stage → 0.2.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 CHANGED
@@ -1,3 +1,245 @@
1
- # Temporary Holding Version
1
+ # itsaplan-cli
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ It's a Plan 的獨立 CLI,入口為 `iap` 與 `itsaplan`。Node.js 22+;API 基線 1.9.0。公開 npm 套件為 `@dac-tech-team-tw/itsaplan-cli`,原始碼維持 private;目前採本機手動發布,GitHub Actions 負責 CI。
4
+
5
+ ## 安裝
6
+
7
+ ```sh
8
+ npm install -g @dac-tech-team-tw/itsaplan-cli
9
+ iap --help
10
+ itsaplan --version
11
+ ```
12
+
13
+ 從原始碼安裝:
14
+
15
+ ```sh
16
+ pnpm install
17
+ pnpm build
18
+ make install-local
19
+ # 或 npm install -g .(也提供原生 Windows 安裝入口)
20
+ command -v iap
21
+ iap --help
22
+ ```
23
+
24
+ 本機 installer 拒絕覆寫其他既有指令,wrapper 使用建置後的絕對路徑,從任何目錄均可執行。原始碼移動後須重新安裝。`~/.local/bin` 須在 PATH。
25
+
26
+ ## 認證與安全邊界
27
+
28
+ API endpoint 必須由呼叫者提供;沒有內建公司 endpoint,不自動載入 `.env`。
29
+
30
+ ```sh
31
+ export ITSAPLAN_URL=https://api.example.com
32
+ # 由外部秘密管理工具注入 ITSAPLAN_API_KEY
33
+
34
+ iap --json doctor
35
+ iap auth status --json
36
+ # 人類互動:隱藏輸入 key,驗證後存入 OS 憑證庫
37
+ iap auth login --api-url https://api.example.com
38
+ # 無桌面環境:明確選擇檔案儲存(明文、限制檔案權限)
39
+ printf '%s' "$ITSAPLAN_API_KEY" | iap auth login --with-token --storage file
40
+ ```
41
+
42
+ Endpoint:`--api-url` > `ITSAPLAN_URL` > 使用者設定。Key:`ITSAPLAN_API_KEY` > 與 endpoint 配對的本機憑證 > 一次性 `--api-key`。env key 或顯式 key flag 必須搭配 env URL 或 URL flag,不能偷偷使用已存 endpoint;flag 可能暴露在 process list,正常使用請選 env 或登入。
43
+
44
+ 首次登入請向服務管理者確認 **API 服務網址**(部署的 API domain,含 `https://` 與必要的 base path),不要填平常開啟的網頁登入網址;不能只填裸 hostname。登入提示會標明預設網址來自 `--api-url`、`ITSAPLAN_URL` 或已儲存設定,手動輸入可覆寫該預設。若 `/me` 回傳 redirect,CLI 仍安全拒絕,不會跟隨或把 key 轉送到目的地;即使手動輸入相同網頁網址也會被拒絕,不代表 key 無效。確認 API 網址後,以 `iap auth login --api-url <API_URL>` 重試;CLI 不猜測 API hostname。
45
+
46
+ 互動登入會在輸入 key 前辨識既有 `ITSAPLAN_API_KEY`,說明後續指令仍受環境設定影響,讓使用者選擇繼續儲存或取消;不修改父 shell 或 shell 啟動設定,也不改變 CI 的憑證優先序。登入驗證/儲存成功不代表後續未帶參數的命令會使用同一身份。`auth status` 區分已儲存憑證的 metadata 與目前生效來源;未實際驗證的已存身份不會宣稱已認證。
47
+
48
+ 一般 `auth login` 成功只在 stdout 顯示 `OK` 與已儲存結果;必要警告以繁體中文輸出至 stderr,不印出完整身份或設定。需要完整資料時加 `--json`,仍保留一個完整 JSON envelope;登入失敗沿用既有錯誤 envelope 與 exit code。提示、環境憑證警告與 redirect 診斷使用繁體中文,旗標、環境變數與錯誤碼名稱不變。
49
+
50
+ 登入的 `data.authenticated`/`data.user` 保留「本次輸入 key 已驗證」的既有語意;`data.saved` 描述已存登入,`data.effective` 描述後續不帶登入旗標的命令。Status 則驗證目前生效身份。兩者的 `verification` 與 `usable` 不混用:`not_run`/`usable:null` 表示尚未確認生效憑證可用,`usable:false` 表示已知阻礙;未檢查的已存 key 使用 `tokenAvailable:null`,不等同沒有 key。
51
+
52
+ 要暫時使用已存登入而不更動目前 shell,POSIX 可執行 `env -u ITSAPLAN_API_KEY -u ITSAPLAN_URL iap auth status --json`;其他平台請在目前 shell 明確移除這兩個變數後再查詢。環境 key 未搭配明確 URL 時仍回報 `EXPLICIT_ENDPOINT_REQUIRED`,絕不將它送往已存 endpoint。
53
+
54
+ macOS 設定在 `~/Library/Application Support/itsaplan/config.toml`;Linux 在 `$XDG_CONFIG_HOME/itsaplan/config.toml`(預設 `~/.config`);Windows 在 `%APPDATA%/itsaplan/config.toml`。設定不含 key;原生憑證庫採 Keychain/Secret Service/Credential Manager。不可用時不自動降級,須明確指定 `--storage file`。POSIX 憑證目錄 0700、檔案 0600;Windows 使用 ACL。完整正規化 base URL(含 path)隔離憑證。`auth logout` 只清除該 endpoint 本機憑證,不撤銷 key,也不能清除外部 env。
55
+
56
+ Login 會先檢查設定檔安全性並準備完整的設定暫存檔,再儲存憑證。後續設定提交失敗時,會還原原憑證或移除本次新憑證,保留其他 endpoint;讀回確認還原後回報 `not_applied`/exit 1。若無法確認還原,則回報 exit 6 與 `data.recovery` 清理位置,不宣稱登入成功或已安全還原。
57
+
58
+ HTTPS 為預設要求,localhost 可用 HTTP。拒絕 URL userinfo/query/fragment、跨 origin redirect、raw 絕對 URL 與路徑逃逸。repo `.itsaplan.toml` 只能設定 `project_ref`;`api_url` 會被拒絕,repo 無權指定憑證目的地。
59
+
60
+ ## 發現、解析、閱讀
61
+
62
+ ```sh
63
+ iap project list --json
64
+ iap project view acme.MKT --json
65
+ iap init --project acme.MKT
66
+ iap issue resolve MKT-42 --project acme.MKT --json
67
+ iap issue view MKT-42 --project acme.MKT --comments --json
68
+ iap issue comments MKT-42 --project acme.MKT --limit 25 --json
69
+ iap issue activity --id 123 --limit 25 --json
70
+ iap issue list --project acme.MKT --assignee @me --limit 30 --json
71
+ iap issue list --project acme.MKT --search 'login' --json
72
+ ```
73
+
74
+ 範例名稱與 ID 皆為虛構。`MKT-42` 的 42 是 project sequence,不是內部 ID;裸數字需要專案範圍。`--id` 與 positional 互斥,已知識別碼直接解析,不先掃清單。跨團隊 key 歧義請指定完整 `team.KEY`。明確識別碼與專案矛盾會拒絕。
75
+
76
+ 目錄專案設定使用最近 `.itsaplan.toml`(到 git root 為止,repo 外不超過 home)。`init --project <team.KEY>` 先驗證專案,只在目前目錄寫入 project_ref;拒絕既有或 dangling symlink,以同目錄暫存檔原子替換設定,不寫穿 symlink 目標。
77
+
78
+ 使用者層級預設專案可跨目錄使用,與完整 API 服務網址(含 path)綁定;切換 endpoint 不會套用另一個伺服器的預設:
79
+
80
+ ```sh
81
+ iap config set project acme.MKT --json
82
+ iap config get project --json
83
+ iap issue list --search 'login' --json
84
+ iap config unset project --json
85
+ ```
86
+
87
+ `set` 先向目前可信 endpoint 驗證專案,保存伺服器回傳的完整 `team.KEY`;`get` 顯示該 endpoint 的預設與目前生效專案及來源;`unset` 只移除該 endpoint 的使用者預設,不刪認證或目錄設定。專案優先序為 `--project` > `ITSAPLAN_PROJECT` > 最近 `.itsaplan.toml` > 該 endpoint 的使用者預設;清除後仍可能由較高優先序來源選定專案。此功能不取代 `init`,也不將 endpoint 或 key 寫入 repo。
88
+
89
+ List/search 預設 30,本地 `--limit` 接受 1–500,但不保證 server 回滿;僅支援 bounded limit,沒有接續分頁(cursor/page),完整性維持 unknown,不提供假 `--all`。Feed 預設 25、最多 100;把回傳 `data.nextCursor` 原樣交給 `--cursor`。`view --comments` 只讀最近 25 個頂層留言與可取得的回覆,並非全部討論。附件只提供 metadata,不代表已讀取內容。
90
+ 所有指令的 help 說明、標題與內建 help/version 說明均以繁體中文顯示;指令、旗標、佔位符、值、API/JSON 欄位名及技術識別字維持原樣。各層 help 顯示繼承的全域選項(含 `--project`/`--json`)、專案來源優先序與全域說明入口 `iap --help`。查末級指令說明請使用 `iap issue view --help`;list 與 view 提供手動 list → view 範例:從清單選出 `KEY-42` 或內部 ID 後明確傳入,`view` 不會從標準輸入自動接收 list 的 JSON。
91
+
92
+ ### Agent 分階段讀取與欄位選取
93
+
94
+ `--summary` 與 `--fields <paths>` 為互斥、明確 opt-in 的資料選取;未指定時保留原有完整輸出。`--json` 只控制 compact JSON 序列化,可與任一選取模式合用。僅支援 `project list/view` 與 `issue list/view/resolve/comments/activity`;其他命令(含寫入與 dry-run)拒絕選取旗標,錯誤結果不投影。
95
+
96
+ ```sh
97
+ # 探索與搜尋:保留完整標題、可讀狀態;先定位再閱讀
98
+ iap project list --summary --json
99
+ iap issue list --project acme.MKT --search 'login' --summary --json
100
+ # Workflow 值按需查詢,不必每張票重印完整 project setup
101
+ iap project view acme.MKT --fields project.ref,columns.id,columns.name,columns.stateType --json
102
+ # 閱讀需求:不截斷正文、驗收條件、自訂欄位或已取得的討論
103
+ iap issue view MKT-42 --project acme.MKT --comments --summary --json
104
+ # 明確的窄查詢;不代表已完整閱讀需求
105
+ iap issue view MKT-42 --project acme.MKT --fields identifier,title,priority --json
106
+ ```
107
+
108
+ 摘要層級:project list 保留 id/ref/name;project view 保留精簡 project 與 columns、issueTypes、labels,以及完整 customFields,其他 setup 資料請選欄位或用完整輸出。Issue list 保留 id/identifier/title/columnId/state;issue view 只縮小巢狀 project metadata,保留其他原始 issue 資料及自訂欄位定義。Resolve 與討論/活動摘要不刪除其資料,避免漏掉討論內容。
109
+
110
+ `--fields` 為資料相對點路徑:list/feed 作用於每個 item,view/resolve 作用於 data;巢狀陣列維持原形,例如 `columns.id,columns.name`。欄位名稱依各命令的固定 schema 驗證,空集合仍能抓到錯字;未知或不安全路徑於 API 請求前拒絕。整個已知欄位(如 `customFields`)可直接選取;未支援的新 server 欄位請用完整輸出。`meta.output` 標明模式、選取欄位(適用)與 `missing` 路徑:已選但 server 未提供的欄位不補 null;null 保留原意,未選欄位不出現在資料中。
111
+
112
+ 選取不會移除 envelope、分頁游標及既有 meta。Issue list 的 `meta.scope` 描述本次專案與搜尋/負責人範圍;取得 setup 時使用其 canonical ref,否則保留請求 ref。其餘 issue 讀取的 scope 保留 issueId、identifier、projectId 及可得 projectRef;view 即使只指定 `--id`,也保留後續取得的 canonical projectRef。Issue view 的 `meta.read.comments` 區分 `not_read` 與 `read_page`,後者另附 nextCursor;其 limit、returned、completeness 統一讀取 `meta.comments`。附件為 `metadata_only`、`contentRead:false`。Comments/activity 的 `meta.read.entries` 描述 status、contentRead、filter 與輸入/下一頁游標,筆數與完整性統一讀取既有 `meta.limit/returned/completeness`,其 attachments 為 `not_read`。`--fields` 不能移除這些讀取範圍標記。`nextCursor:null` 仍不代表 issue list 完整。
113
+
114
+ Issue list 摘要或選取 `state`/`state.*`,會共用最多一次額外 project setup GET;搭配負責人篩選則重用既有 setup。List 的 state 僅支援 id/name/stateType/unavailable;color、WIP 等完整欄位請用 project view 或 issue view 查詢。未知 columnId 保留 ID 並標示 `unavailable:true`,不猜測狀態;即使只選 `state.name`,仍保留診斷用 id/unavailable,且將 name 標為 missing。只選其他欄位不增加這項請求。投影不改變其他既有讀取流程,不代表減少 HTTP payload,也不新增持久快取。多票共用同一份已讀 workflow 上下文即可;修改前仍須讀取最新相關資訊,既有寫入 preflight 不使用該上下文取代查證。
115
+
116
+ 驗收以相同 fixture、相同 compact serializer 比較完整/分階段整個任務的 UTF-8 stdout bytes(含 LF)、API/CLI 呼叫次數與需求保留正確性。不能只看單次回應或行數;沒有指定 tokenizer/model 實測時不宣稱 token 節省比例。
117
+
118
+ ## 預覽與寫入
119
+
120
+ 先讀 issue 與討論,判斷需求,再依使用者授權寫入。釐清事項不代表已開始或完成,CLI 不自動改狀態。
121
+
122
+ ```sh
123
+ iap issue comment MKT-42 --project acme.MKT --agent codex --body '已確認問題' --dry-run --json
124
+ iap issue comment MKT-42 --project acme.MKT --agent codex --body-file findings.md --json
125
+ iap issue edit MKT-42 --project acme.MKT --agent codex --state-type started --dry-run --json
126
+ iap issue edit MKT-42 --project acme.MKT --human --add-label Bug --remove-label Question --json
127
+ ```
128
+
129
+ `--body-file -` 明確讀 stdin,與 `--body` 互斥。缺參數不會開 editor 或在非互動模式等待輸入。留言可用 `--reply-to <comment-id>`;CLI 驗證留言屬於該 issue。
130
+
131
+ Edit 支援 title、body、state/state-type/column-id、assignee/remove-assignee、priority/remove-priority、type/remove-type,以及可重複 add-label/remove-label。只 PATCH 明確指定的欄位。名稱須精確且不歧義,所有 ID 必須屬於該專案。同 stateType 多個欄位時需指定欄位;不能任選第一個。Label add/remove 保留既有集合,但讀改寫並非原子操作,無 ETag 保證。
132
+
133
+ 所有 comment/edit(含只改欄位與 dry-run)要求 `--agent codex|claude`、有效 `ITSAPLAN_AGENT` 或明確 `--human`。Flag agent 優先於有效 env;human 與任何 env agent 衝突。留言由 CLI 加 `— by Codex via iap`,description 編輯只維護末尾 `— last edited by Codex via iap`,不刪正文引用。只改欄位不額外變更描述或留言。來源是呼叫者宣告,不是可稽核身份。
134
+
135
+ Dry-run 可以讀取驗證但不寫入,顯示身份、request 與 diff;權限/WIP 等仍以真正寫入為準。正常寫入不再詢問 y/n。寫入不重試;timeout/5xx/回應損壞可能已套用,須先讀 issue/feed 查證,不能直接重送。
136
+
137
+ ## 文件發布與 ticket 關聯
138
+
139
+ ```sh
140
+ iap document create --project acme.MKT --title '調查結果' --body-file findings.md --visibility private --agent codex --dry-run --json
141
+ # 以下為寫入示例,取得授權後才移除 --dry-run
142
+ iap document create --project acme.MKT --title '規格' --body '# 規格內容' --visibility project --agent codex --dry-run --json
143
+ printf '# 驗證報告\n' | iap document create --project acme.MKT --title '驗證報告' --body-file - --visibility private --human --dry-run --json
144
+ iap document view 501 --project acme.MKT --json
145
+ iap issue link-document MKT-42 --project acme.MKT --document 501 --agent codex --dry-run --json
146
+ iap issue documents MKT-42 --project acme.MKT --json
147
+ iap document issues 501 --project acme.MKT --json
148
+ ```
149
+
150
+ `document create` 要求明確指定 `--visibility private|project`,不套用伺服器的公開預設。`project` **只對專案中有文件存取權的人可見,不是網際網路公開**;`private` 僅文件擁有者可見。關聯不會放寬文件權限,ticket 文件清單只包含呼叫者可見的文件。標題 1–255 字元,最終 Markdown(含 agent footer)最多 250000 字元;`--body` 與 `--body-file` 互斥,stdin 只由 `--body-file -` 讀取。
151
+
152
+ 建立結果提供穩定 `documentId`、`projectId`、`projectRef` 與可見範圍。Agent 文件附加 `— by Codex via iap`/Claude;human 保留原文。文件建立及兩類關聯都要求來源宣告,關聯只記錄 `meta.actor`,不額外修改 ticket 或發留言。來源仍是呼叫者宣告,不是稽核身份。
153
+
154
+ `issue link-document` 支援識別碼、專案內序號或 `--id`,驗證文件與 ticket 的 numeric project ID 相同;封存文件不可新建關聯。已存在的關聯回傳 `alreadyLinked:true`、`changed:false`,不重送 POST;正常執行為 `not_applied/passed`,預覽為 `not_applied/not_run`。競爭期間伺服器回傳 409 時明確回報衝突,不偷偷重送。
155
+
156
+ ### 既有 PR/MR
157
+
158
+ ```sh
159
+ iap issue repositories MKT-42 --project acme.MKT --json
160
+ iap issue pull-requests MKT-42 --project acme.MKT --repository 17 --state all --page 1 --json
161
+ iap issue link-pr MKT-42 --project acme.MKT --repository 17 --number 83 --agent codex --dry-run --json
162
+ iap issue development MKT-42 --project acme.MKT --json
163
+ ```
164
+
165
+ 先從 `repositories` 選已連接的 repository ID,再從 `pull-requests` 選 PR/MR number。清單一次一頁,`--state open|all`,以真實 `data.nextPage` 繼續查詢;不是全 repository 的完整歷史。`link-pr` 使用已連接 repository ID+正整數 number,**不接受任意 PR URL、不建立新 PR**;已關閉/合併 PR 也可由伺服器以 number 查證,不受第一頁 open 清單限制。預覽不呼叫 POST,因此不保證該 number 存在或仍可連結。
166
+
167
+ 結果保留穩定 `linkId` 與 repository/number 身份;寫入前已觀察到的 PR 關聯是明確 no-op。`alreadyLinked` 只反映 preflight 讀取結果,不保證寫入期間沒有其他人或 webhook 建立關聯。伺服器對相同 ticket/provider/repository/number 使用 upsert,競爭不會新增重複關聯;CLI 不從回應猜測競爭時誰先建立。`changed:true` 表示本次寫入已被接受,並非保證新增了一筆關聯。
168
+
169
+ API 的 development link 沒有 immutable repository ID,CLI 依 provider/repository 名稱/PR number 核對身份。Repository 改名或轉移、連接記錄名稱尚未同步時,回應名稱可能與探索結果不符;此時即使 POST 已成功,也會保守回報 `applied/failed` 並保留取得的 `linkId`。請先用 `issue development` 查證並請管理者確認連接記錄;不要把不同名稱猜成同一 repository,也不要自動重送。
170
+
171
+ 文件建立需要 documents create,讀取需要 documents read;文件關聯需要 documents 與 work_items 的 edit,查詢關聯需要兩者 read。Repository/PR 探索及 PR 關聯需要 repositories edit(即使探索使用 GET);讀取 ticket development 則依 work_items read。Dry-run 不保證所有寫入權限,正式寫入仍由伺服器裁定。
172
+
173
+ 所有新寫入沿用 outcome/verification 與不自動重試契約。`unknown` 或 `applied/failed` 時,先用 `document view`、雙向文件清單或 `issue development` 查證;建立文件尚無 ID 時,用唯讀 `api /projects/{ref}/documents` 尋找,但不可把同名文件當作已證實的本次結果,也不可自動重送。
174
+
175
+
176
+ ## Raw API
177
+
178
+ ```sh
179
+ iap api /me --json
180
+ iap api /projects/acme.MKT --method GET --json
181
+ iap api /some-resource --method POST --input payload.json --dry-run --json
182
+ ```
183
+
184
+ 共用可信 endpoint、認證、redaction 與結果契約。禁止 raw 寫入 `/issues`、`/projects/{project}/issues` 及其子路徑,也禁止 `/comments`、`/checklists`、`/worklogs`、`/attachments` 等 issue 子資源寫入;包含 move、archive、fields 與 bulk labels。另禁止 `/projects/{project}/documents` 及其子路徑的 raw 寫入,避免文件發布及關聯繞過來源宣告。請走高階指令;尚未提供的上述 mutation 暫不支援,GET/HEAD 仍可用。其他 raw write 不保證 agent footer,僅在使用者明確授權該操作時執行。
185
+
186
+ ## JSON 契約
187
+
188
+ `--json` 可放在指令前後;stdout 恰一個 JSON 文件,診斷走 stderr。所有家族用 CLI envelope,非直接 API pass-through;raw `data` 是移除敏感欄位後的 API 回應。
189
+
190
+ ```json
191
+ {"ok":true,"data":{"id":123,"identifier":"MKT-42"},"meta":{"schemaVersion":1,"apiVersion":"1.9.0"}}
192
+ ```
193
+
194
+ 列表 `data` 為 `{ "items": [], "nextCursor": null }`,`meta` 包含 returned、completeness 及適用的 limit。PR 清單改用真實 `nextPage`,不提供假 cursor;`null` cursor 不等於所有列表皆完整。doctor/auth/config/init/project/issue/document/api 全部遵循相同 envelope;上方各家族命令可直接加 `--json`。
195
+
196
+ ```json
197
+ {"ok":false,"error":{"code":"ACTOR_REQUIRED","message":"Provide --agent or --human","retryable":false},"outcome":"not_applied","verification":"not_run","data":null,"meta":{"schemaVersion":1}}
198
+ ```
199
+
200
+ 寫入根層 `outcome`:applied/not_applied/unknown;`verification`:passed/failed/not_run。Dry-run 成功是 not_applied/not_run。已知寫入但驗證失敗為 applied/failed、`ok:false` 並保留已取得 ID。未知結果為 unknown/not_run,applied/unknown 的 retryable 永遠 false。寫入 `data` 回報 action、issueId、commentId/documentId/linkId(適用)、changed 與可得 updatedAt;預覽另有 dryRun、request 及適用的 diff,`meta.actor` 記錄來源。
201
+
202
+ Raw 與高階 issue 寫入共用失敗分類,不以其他 HTTP status 推翻 transport 明確回報的 `unknown`。例如 410/412 未被判定為確定拒絕時,維持 `unknown`/exit 6,而不是同時宣稱未套用。
203
+
204
+ Exit:0 成功(含空集合)、1 API/network、2 輸入/歧義/不支援、3 認證、4 權限、5 衝突、6 寫入待查證。Provider code 在 error.apiCode,HTTP status 在 error.status。Doctor 缺 key 仍提供診斷 data,exit 非零。較新 server 可嘗試核心指令,doctor 標記版本尚未驗證。
205
+
206
+ 裸 project key 跨團隊歧義回報 `AMBIGUOUS_PROJECT`/exit 2;一般 409(包含 WIP 衝突)仍為 exit 5。基線服務沒有提供歧義專用 code,因此只辨識 project GET 查詢中與請求 key 完全相符的已知上游訊息,不把所有 409 當成歧義。
207
+
208
+ ## 開發與發佈
209
+
210
+ ```sh
211
+ pnpm format
212
+ pnpm build
213
+ pnpm typecheck
214
+ pnpm test
215
+ npm pack --dry-run --json
216
+ ```
217
+
218
+ 測試使用本機 HTTP fixture 與 fake client,不呼叫 production 寫入。npm `files` allowlist 只含 dist 與 README(npm 另含 package metadata),不發布開發 OpenAPI、設計稿、AGENTS、本機設定或 secrets。`publishConfig.access=public`;private GitHub repo 不代表 npm 內容私有。未實測的平台不得據此宣告支援;macOS/Windows 原生憑證庫、ACL 與安裝仍需各平台實測。
219
+
220
+ ### npm 發布
221
+
222
+ 使用 **GitHub CI + 本機手動發布**,操作步驟與失敗處理見 [DEPLOY.md](DEPLOY.md)。每次以版本 PR 更新 package version、合併並確認 main CI 後,在乾淨的 main checkout 執行 `pnpm run release`,會自動測試、打包/安裝驗證並透過互動式 npm 發布同一份 tarball;`pnpm run release --dry-run` 只驗證、不發布,也不要求新版本或乾淨 main。正式發布不自動加版號或重送,仍須完成 npm/2FA 及發布後 registry 安裝驗證。
223
+
224
+ 不需要 GitHub 付費方案、tag ruleset 或 Trusted Publisher。原始碼 private、npm package public;明確關閉不支援 private repo 的 provenance。既有 Release 工作流保留但 `NPM_RELEASE_ENABLED` 維持未啟用,不因合併 main 或 push tag 自動發布。日後改用 OIDC 必須另行完成設定。
225
+
226
+ ### 已執行驗證
227
+
228
+ - #11/#12(含 PR #15 review 修正):build、型別檢查與 63 個相關 output/issue/實際 CLI 測試通過,涵蓋 internal ID view 的 canonical 專案範圍、list state 欄位驗證與未知狀態巢狀投影診斷。Linux 本機 HTTP fixture 的相同雙票流程(compact JSON,含 LF)完整輸出累計 28531 bytes、11 次 API/5 次 CLI;分階段輸出 18825 bytes、12 次 API/5 次 CLI。正文、自訂欄位、checklists、討論及附件 metadata 保持一致;多一次 API 為搜尋可讀狀態的 setup GET。未量測 tokenizer/model token,未呼叫正式 API 或發布 npm 套件。
229
+
230
+ - #10 help 繁體中文化:打包安裝檢查不再依賴英文 `Usage:` 文案;Linux 隔離安裝 tarball 後,`iap`/`itsaplan` 的 help、version 與無認證 doctor JSON 驗證通過,未發布 npm 套件或呼叫正式 API。
231
+
232
+ - PR #13 登入 review 調整:build、型別檢查與 48 個相關測試通過。實際 Node CLI/本機 fixture 驗證一般登入只印簡短結果、警告走 stderr、`--json` 保留完整 envelope;Linux TTY 驗證繁中提示、預設網址來源、手動覆寫成網頁網址後安全拒絕 307,且失敗不覆蓋已存 API 網址。未呼叫正式 API。
233
+
234
+ - #7/#8/#9:build、型別檢查與 75 個相關測試通過。本機 HTTP fixture 驗證實際 CLI 的 redirect 拒絕、已存/生效身份、環境 key 缺 URL 時零請求、跨目錄預設專案及清除後保留認證;Linux TTY 實測登入衝突提示、取消與繼續儲存、隱藏 key 輸入。未呼叫正式 API,未據此宣稱 Windows/macOS 互動流程已實測。
235
+
236
+ - 2026-11-11:以本機手動流程發布 `@dac-tech-team-tw/itsaplan-cli@0.1.0`;registry latest、metadata integrity、下載 tarball 與原始 receipt 一致。Linux 從 npm 安裝後,兩個 bin 的 help、version、無認證 doctor JSON 通過;發布前 build、typecheck、146 個既有測試與 20 個發布/tarball 測試通過。完整紀錄見 [DEPLOY.md](DEPLOY.md)。[main CI](https://github.com/dac-tech-team-tw/itsaplan-cli/actions/runs/42779451450) 已通過;未啟用或宣稱實測 OIDC 自動發布。
237
+ - 本次 build、型別檢查及 113 個相關案例通過,涵蓋文件發布、文件/PR 關聯、權限/專案邊界、未知寫入結果、CLI stdin、重複關聯不重送及既有 issue/raw API/認證回歸路徑。
238
+ - 部署中的公開 OpenAPI 1.10.0 已核對本次相關 request/response schema 與權限宣告,與本機 1.9.0 契約相容;未對正式環境做文件或關聯寫入,也未驗證使用者實際獲授的寫入權限。
239
+ - Linux 從 `/tmp` 執行已安裝的 `iap document create --help`、`itsaplan issue link-pr --help`;本機 HTTP fixture 驗證實際 CLI 發布與關聯流程。
240
+ - Linux 從 `/tmp` 執行已安裝的 `iap`/`itsaplan`;缺可信 endpoint 時 doctor 拒絕發送環境 key。
241
+ - 本次五項修正另從 `/tmp` 以已安裝命令及本機 HTTP fixture 驗證;未呼叫正式 API。曾發現 `init --project` 的重複參數宣告會擋住執行,已一併修正並加入實際 CLI 回歸驗證。
242
+ - 正式 API 1.10.0:doctor、project list/view、issue list/view/comments 與 comment dry-run 通過,未執行正式寫入。這些 smoke checks 不代表整個 1.10.0 API 已驗證。
243
+ - Linux 原生憑證庫以非秘密 fixture 值完成 set/get/delete;檔案儲存與登入/登出流程由隔離測試驗證。互動隱藏輸入、macOS/Windows 原生認證及 Windows ACL 仍需實機驗證。
244
+ - `npm pack --dry-run --json` 僅列出 README、package.json 與 dist,沒有本機憑證、公司設定或開發規格。
245
+ - Companion skill 原始碼位於 [`skills/itsaplan/SKILL.md`](skills/itsaplan/SKILL.md);可安裝至 `~/.codex/skills/itsaplan/SKILL.md`。
package/dist/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};