@tocca-systems/twp-cli 0.18.0 → 0.20.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.
Files changed (36) hide show
  1. package/CHANGELOG.public.md +20 -0
  2. package/README.md +70 -6
  3. package/dist/{ai-dispatch-27EZS2S3.js → ai-dispatch-PNA4UF4I.js} +2 -2
  4. package/dist/{api-command-BH6ILQNX.js → api-command-2OPQMSTE.js} +24 -24
  5. package/dist/{app-4LRDLLTV.js → app-FZT4U3VG.js} +146 -82
  6. package/dist/auto-update-CV2MM32C.js +4 -0
  7. package/dist/auto-update-worker-ML7EBNQW.js +16 -0
  8. package/dist/{backlog-AYEKG575.js → backlog-NV7Z76R3.js} +1 -1
  9. package/dist/{chunk-U4QQNRXF.js → chunk-3SNMDSCW.js} +22 -22
  10. package/dist/chunk-3WHC4FSG.js +15 -0
  11. package/dist/chunk-5WGOHFAS.js +3 -0
  12. package/dist/{chunk-SQSVA6AT.js → chunk-BYRM4NSC.js} +1 -1
  13. package/dist/chunk-DEVIQH5U.js +18 -0
  14. package/dist/{chunk-RQFG3OUL.js → chunk-FOFV2MNL.js} +1 -1
  15. package/dist/chunk-GTABFTZP.js +23 -0
  16. package/dist/chunk-ILKQDXI5.js +22 -0
  17. package/dist/{chunk-7WEYBZSK.js → chunk-MIMDLO52.js} +1 -1
  18. package/dist/{chunk-H3JTPDCJ.js → chunk-NWABK3RZ.js} +3 -18
  19. package/dist/chunk-OVYHOZ3C.js +27 -0
  20. package/dist/{chunk-77CQG7O7.js → chunk-SPZO6C5N.js} +27 -24
  21. package/dist/{chunk-FKIZ5ZJU.js → chunk-TAN5I2DP.js} +2 -2
  22. package/dist/{chunk-63LDNYGW.js → chunk-XNLIEUAW.js} +1 -1
  23. package/dist/chunk-ZGG7TRAM.js +3 -0
  24. package/dist/cli.js +18 -34
  25. package/dist/{commands-VUWI4ERO.js → commands-7D5EEQBY.js} +6 -5
  26. package/dist/{commands-XYKBLMXT.js → commands-EWRHQZYM.js} +56 -61
  27. package/dist/logout-guard-Q4MQFEGR.js +13 -0
  28. package/dist/{oneshot-5EM5NFTK.js → oneshot-AXS5LWUY.js} +2 -2
  29. package/dist/{project-OKTJ32JT.js → project-BATJQR3F.js} +1 -1
  30. package/dist/run-2OQQAOHL.js +4 -0
  31. package/dist/{setup-AJ56N6XO.js → setup-ROGEF3UO.js} +2 -1
  32. package/dist/{task-VVBXZLPU.js → task-6QUH5OXF.js} +2 -2
  33. package/dist/update-EXFIHTMW.js +3 -0
  34. package/package.json +1 -1
  35. package/dist/run-XALXQIC3.js +0 -4
  36. package/dist/update-WDWUECN7.js +0 -21
@@ -11,6 +11,26 @@
11
11
  `CHANGELOG.md` に残してあります。顧客向けの履歴は public 公開以降を対象とします。
12
12
  -->
13
13
 
14
+ ## 0.20.0
15
+
16
+ TUI のスラッシュコマンドに `/tasks`(タスク一覧)・`/task <キー>`(タスクの詳細)・`/projects`(プロジェクト一覧)を追加しました。AI を動かさずに結果を表示するので、クレジットは消費しません。
17
+
18
+ 自分用のスラッシュコマンドを markdown で追加できるようになりました。`.twp/commands/<名前>.md`(そのリポジトリ)か `~/.twp/commands/<名前>.md`(自分の全プロジェクト)に置くと `/<名前>` で呼べます。本文の `$ARGUMENTS` / `$1`〜`$9` は引数に置き換わります。
19
+
20
+ いずれも TUI の中だけの機能で、`twp -p` では解釈しません。
21
+
22
+ 入力中に `@` を打つとファイルの候補が出ます(Tab で確定)。送信すると `@パス` のファイルの中身が、`#ABC-123` のようなタスクキーはそのタスクの内容が AI へ添付されます。
23
+
24
+ `twp task` / `twp project` などのコマンドで、`--query` で取り出した token / secret / api_key / password などの値も伏字にするようになりました。値そのものが要るときは、`twp api` と同じく `--no-redact` を付けてください。
25
+
26
+ ## 0.19.0
27
+
28
+ **`twp logout` が、同じ資格情報で動いている `twp task-loop` を止めてしまわないようにしました。** 同じマシンで同じプロファイルの task-loop が動いているときは、ログアウトせずに理由と影響(そのループが止まること・もう一度 `twp login` が必要になること)をお知らせします。それでもログアウトする場合は `twp logout --force` を使ってください。
29
+
30
+ **自動アップデートに対応しました。** `npm i -g @tocca-systems/twp-cli` で導入した twp は、1日1回新しい版を確認し、twp を終了したあとに自動で更新します(次に起動したときから新しい版で動きます)。更新後の初回起動では、何版から何版へ上がったかを1行でお知らせします。更新に失敗しても、いまの版のまま問題なく使えます(理由と手動の更新方法を1回だけお知らせします)。
31
+
32
+ 自動アップデートを止めるには、環境変数 `TWP_NO_AUTO_UPDATE=1` を設定するか、`~/.twp/config.json` に `"auto_update": false` を書いてください。npx やプロジェクトへのローカル導入で使っている場合は自動では更新せず、新しい版があることだけをお知らせします。
33
+
14
34
  ## 0.16.0
15
35
 
16
36
  `twp task-loop` が、使っている AI アカウントの枠(利用率・上限・再ログイン期限)をエージェントループ画面へ報告できるようになりました。**設定しなければ何も変わりません**(プローブの実行も送信も起きません)。
package/README.md CHANGED
@@ -21,8 +21,10 @@ TWP(Tocca Working Platform)を、ターミナルから使うための CLI
21
21
  | **できる** | AI との会話(ストリーミング表示)。手元のファイルの読み書き・検索、コマンド実行、git の読み取り——いずれも**実行前に確認**します |
22
22
  | **できる** | `twp project` / `twp task` によるプロジェクト・タスクの読み書き(一覧・取得・作成・更新・削除・コメント) |
23
23
  | **できる** | `twp task-loop` による、TWP のタスクキューを手元の AI CLI に実行させる常駐ループ |
24
- | **まだできない** | **会話中の AI から TWP のデータを直接参照・操作すること。** 「このタスクの内容を読んで」と会話で頼むことはまだできません。TWP のデータを扱うときは `twp task` などのコマンドをお使いください |
25
- | **まだできない** | TWP の操作を行うスラッシュコマンド(`/task` など)。現在使えるスラッシュコマンドは `/help` `/mode` `/model` `/clear` `/context` `/doctor` `/exit` の7つと、動作デモの `/demo` です |
24
+ | **できる** | スラッシュコマンド: `/help` `/mode` `/model` `/clear` `/context` `/doctor` `/exit` `/demo`(動作デモ) `/tasks` `/task` `/projects`。`/tasks` などの TWP 系は `twp task list` と同じ結果を画面に出すだけで、AI は動かしません(クレジットも消費しません)。スラッシュコマンドは TUI の中だけで使えます(`twp -p` では解釈しません) |
25
+ | **できる** | 自分用のスラッシュコマンドを markdown で追加すること(`.twp/commands/*.md` / `~/.twp/commands/*.md`・[下記](#スラッシュコマンドを自分で足す))。入力中の `@パス` でファイルを、`#ABC-123` でタスクの内容を AI へ添付できます |
26
+ | **まだできない** | **会話中の AI が自分から TWP のデータを参照・操作すること。** AI に読ませたいタスクは `#ABC-123` と書いて添付してください。起票・更新などの操作は `twp task` コマンドをお使いください |
27
+ | **まだできない** | タスクの起票・コメント・通知などを行うスラッシュコマンド(`/task-new` `/comment` `/inbox` など)。同じ操作は `twp task create` / `twp task comment create` で行えます |
26
28
 
27
29
  登録されていないコマンドは補完にも `/help` にも出しません。**「あるのに動かない」ものは置かない**方針です。
28
30
 
@@ -44,8 +46,9 @@ twp -p "<プロンプト>" 非対話で 1 往復だけ実行(応答は stdout
44
46
  twp login ログイン(ブラウザ委譲 / --password / --token)
45
47
  twp login --tenant <code>
46
48
  テナントコードを先に指定する(--password のプロンプトを 1 つ省ける)
47
- twp logout / whoami
48
- twp update npm の最新版と、サーバが要求する最小バージョンを確認
49
+ twp logout ログアウト(同じ資格情報で twp task-loop が稼働中なら拒否する。--force で続行)
50
+ twp whoami ログイン中のユーザー・テナントを表示
51
+ twp update npm の最新版・サーバが要求する最小バージョン・自動更新の状態を確認
49
52
  twp --mode biz 起動時のモードを指定(dev | biz | plan)
50
53
  twp --permission-mode denyAll
51
54
  ツール実行の既定を上書き(plan | acceptEdits | denyAll)
@@ -108,6 +111,8 @@ twp task label list [--project <コード>]
108
111
 
109
112
  グローバルオプション: `--profile <名前>` / `--output <json|table|text|tsv>` / `--query <JMESPath>` / `--dry-run` / `--debug` / `--yes` / `--refresh`。**`--output json` は常に API の生のレスポンス**を返します(表示用に間引きません)。
110
113
 
114
+ 応答に載る token / secret / api_key / password などの値は、`--query` で取り出したものも含めて**既定で伏字**にして出します(出力は端末やログに平文で残るため)。値そのものが要るときは各操作に `--no-redact` を付けてください(`twp api` と同じ意味です。エラー出力は常に伏字のままです)。
115
+
111
116
  ```bash
112
117
  twp task list --project ACME --status 進行中 --output json --query '[].{key:key,subject:subject}'
113
118
  ```
@@ -170,9 +175,39 @@ twp task-loop stop
170
175
 
171
176
  **モデル取次には `cli` 権限付きトークンが必要。** `twp login`(ブラウザ委譲)と `twp login --password` が発行する。`twp login --token` で保存した通常トークンは TWP API には使えるが会話は 401 になる。
172
177
 
173
- ### 更新(`twp update`)
178
+ ### 自動アップデート
179
+
180
+ **`npm i -g @tocca-systems/twp-cli` で導入した場合、twp は自動で最新版へ更新される(既定で有効)。**
181
+
182
+ - 24時間に1回、バックグラウンドで npm registry の最新版を確認する(起動は待たせない)
183
+ - 新しい版があれば、**起動した twp が終了してから** `npm i -g @tocca-systems/twp-cli@<最新版>` を実行する。効くのは**次回起動から**で、実行中の twp は差し替えない
184
+ - 更新後の初回起動で `twp を 0.18.0 から 0.19.0 へ自動更新しました` のように stderr へ1行出す
185
+ - **失敗しても現在の版のまま動く。** 権限不足(グローバルの導入先に書けない)・registry 不達のときは、次回起動時に理由と手動の更新方法を1回だけ知らせる
186
+ - 通知はすべて stderr に出す(`--output json` の stdout は汚さない)
187
+
188
+ **無効化**(どちらでもよい。無効化すると確認の通信も起きない):
189
+
190
+ ```bash
191
+ export TWP_NO_AUTO_UPDATE=1
192
+ ```
193
+
194
+ ```jsonc
195
+ // ~/.twp/config.json
196
+ { "auto_update": false }
197
+ ```
198
+
199
+ | 導入のしかた | 挙動 |
200
+ |---|---|
201
+ | `npm i -g`(npm のグローバル導入) | 自動で更新する |
202
+ | npx / プロジェクトへのローカル導入 / pnpm | 更新しない。新しい版があることと更新方法を、版ごとに1回だけ知らせる |
203
+ | ソースから実行(`node dist/cli.js` 等) | 何もしない |
204
+ | `CI` が設定された環境 / `twp task-loop` とその配下 | 何もしない |
205
+
206
+ グローバル導入かどうかは、実行中の `cli.js` の実体パスが `npm root -g` 配下にあるかで判定する。状態は `~/.twp/update-state.json` に残る(消すと次回起動で確認し直す)。
207
+
208
+ ### 更新の確認(`twp update`)
174
209
 
175
- `twp update` は **npm の最新版**と、**接続先のリレーが要求する最小サポートバージョン**の両方を報告する。**自分では更新しない**(インストール方法・権限が環境で違うため、実行すべきコマンドを表示する)。最小サポート未満なら終了コード 1。
210
+ `twp update` は **npm の最新版**と、**接続先のリレーが要求する最小サポートバージョン**の両方を報告し、自動アップデートが効いているかも表示する。**このコマンド自身は更新を実行しない**(実行中の自分を差し替えないため。更新は上の自動アップデートが行う)。最小サポート未満なら終了コード 1。
176
211
 
177
212
  リレーは古いクライアントを拒否しない(`/api/cli/v1` の後方互換は恒久的に保つ)。止めるのは CLI 側で、**下限が読めない・取れないときは素通りする**(回線断やサーバ未対応で全員が使えなくなるのを避ける)。下限は `~/.twp/models.json` にプロファイル単位でキャッシュする。
178
213
 
@@ -187,6 +222,7 @@ twp 0.2.3
187
222
 
188
223
  最新版 0.3.0(npm registry)
189
224
  最小サポート 0.2.0(サーバ / https://ai-api.tocca.systems)
225
+ 自動更新 有効(npm グローバル導入・24時間ごとに確認し、次回起動から反映)
190
226
  判定 更新できます(必須ではありません)
191
227
 
192
228
  npm i -g @tocca-systems/twp-cli@latest
@@ -246,6 +282,7 @@ twp login
246
282
  |---|---|
247
283
  | `Shift+Tab` / `Alt+M` | モード巡回(開発 → 業務 → プラン) |
248
284
  | `/` | スラッシュコマンドパレット(ファジー絞り込み・`Tab` 補完・`↑↓` 選択) |
285
+ | `@` | ファイルの候補(`.gitignore` の対象は出ない・`Tab` で確定)。送信すると中身が AI へ添付される(空白や `@` を含む名前は候補に出ない) |
249
286
  | `Shift+Enter` / `Ctrl+J` / `\` + `Enter` | 改行(複数行入力) |
250
287
  | `Ctrl+R` | 直前のツール出力を全文展開 |
251
288
  | `Ctrl+C` | 実行中なら中断 / 入力が空なら 2 回で終了 |
@@ -292,6 +329,33 @@ permissions:
292
329
  - **書き間違えても起動は止まらない。** 読めなかった項目は警告を出して既定へ戻る。起動時に `⚠ モード定義:` が出たらその行を直す
293
330
  - いま何が効いているかは `/context` で確認できる(どのファイルが効いているか・有効ツール glob・常駐ツールの実体が出る)
294
331
 
332
+ ### スラッシュコマンドを自分で足す
333
+
334
+ **`.twp/commands/<名前>.md`**(そのリポジトリで作業する全員に効く)か **`~/.twp/commands/<名前>.md`**(自分の全プロジェクトに効く)に置くと、`/<名前>` で呼べるようになる。サブディレクトリに置いた `git/summary.md` は `/git:summary` になる。**同じ名前なら自分の `~/.twp/commands/` が強い**(リポジトリが、普段使っている自分のコマンドを差し替えられないように。モードとは逆)。
335
+
336
+ **TUI(`twp` を引数なしで起動した画面)だけの機能です。** `twp -p` ではスラッシュコマンド・`@パス`・`#ABC-123` を解釈せず、文字列のまま AI へ送ります(`twp -p "/tasks"` はクレジットを消費する会話になります。一覧は `twp task list` を使ってください)。
337
+
338
+ ```markdown
339
+ ---
340
+ description: 差分をレビューする
341
+ argument-hint: <観点>
342
+ allowed-tools: [read_file, grep, git]
343
+ mode: dev
344
+ ---
345
+ いまの作業ツリーの差分を $ARGUMENTS の観点でレビューしてください。
346
+ 規約は @CONTRIBUTING.md を見てください。
347
+ ```
348
+
349
+ - **本文はそのまま AI への依頼になる**(呼ぶたびに会話1ターンぶんのクレジットを消費する)。`$ARGUMENTS` は打った引数全体、`$1`〜`$9` は1語ずつ(`"…"` で空白を含められる)。どちらも書いていないのに引数を渡すと、本文の末尾に添えて送る
350
+ - `@パス` は、そのファイルの中身を添付する(通常の会話入力でも同じ)。**AI にファイルを読ませるときと同じ確認・拒否が掛かる**——作業ディレクトリの外、`.env` や SSH 鍵などは添付されない
351
+ - `#ABC-123` は、送信時にタスクの件名・ステータス・担当・本文を取得して添付する(通常の会話入力でも同じ)
352
+ - front-matter は省略できる(省略すると本文の1行目が説明になる)。使えるキーは `description` / `argument-hint` / `allowed-tools` / `mode`
353
+ - `mode` を書くと、そのモードでだけ候補に出る(`mode: biz` なら開発モードでは出ない)
354
+ - **`allowed-tools` は AI が使えるツールを絞るだけ**で、確認を省略しない(書かなければモードの既定どおり)。書けるのはツール名(`read_file` / `grep` / `Read` / `Bash(git status:*)` など。括弧の中は見ない)。本文に書いた `@パス` の添付は、AI のツールではなく利用者の操作として扱うので `allowed-tools` に左右されない
355
+ - **組み込みのコマンド(`/help` `/clear` など)は上書きできない**
356
+ - **リポジトリ側(`.twp/commands/`)の定義は、clone しただけで読まれる。** 呼び出したときには「リポジトリに同梱された定義である」ことを添えて AI へ渡し、権限・確認の手順を変える指示としては扱わせない。パレットと `/help` には、どのファイル由来かが出る
357
+ - **書き間違えても起動は止まらない。** 読めなかったコマンドは登録せず、起動時に `⚠ コマンド定義:` を出す
358
+
295
359
  ### 権限ルール(`~/.twp/settings.json` と `--allowed-tools`)
296
360
 
297
361
  「このコマンドは毎回聞かなくてよい」「このツールは絶対に使わせない」を、Claude Code と同じ記法で書ける。組織で使っている Claude Code の allowlist をそのまま移せる。
@@ -1,7 +1,7 @@
1
1
  import { createRequire as __twpCreateRequire } from 'node:module';
2
2
  const require = __twpCreateRequire(import.meta.url);
3
- import{failureHint,isAuthError,isCliFatalText,isRateLimited,isServerAiType,isUntrusted,maxTurnsReached,rateLimitWaitSeconds,tailForScan}from"./chunk-ZOOEH7ZE.js";import{DEFAULT_CLAUDE_LAUNCHER,activeSlotPath,detectAiClis,detectClaudeAutoSwitch,isClaudeAi,isUsableModelId,modelFitsRoute,resolveSpawnTarget,usesBedrock,wrapWithAutoSwitch}from"./chunk-H3JTPDCJ.js";import{isForceOnly,killProcessTree,system32}from"./chunk-N2UVRM3Z.js";import{findExecutable,isWindowsDriveAbsolute}from"./chunk-PMOUHEJQ.js";
4
- import{stripTerminalControls}from"./chunk-NHYMHCAT.js";import"./chunk-VSJBJXZO.js";import{spawnSync}from"child_process";import fs2 from"fs";import path2 from"path";import{spawn}from"child_process";import fs from"fs";import path from"path";var FINAL_REPORT_BEGIN="<<<AI_FINAL_REPORT>>>";var FINAL_REPORT_END="<<<END_AI_FINAL_REPORT>>>";var ClaudeStreamRenderer=class{constructor(now=()=>new Date){this.now=now}now;toolNames=new Map;toolCount=0;result={subtype:null,isError:null,numTurns:null,costUsd:null,durationMs:null,tokensIn:null,tokensOut:null,rateLimited:false,resetsAt:null,finalText:""};push(line){const trimmed=line.trim();if(trimmed==="")return[];let event;try{const parsed=JSON.parse(trimmed);if(parsed===null||typeof parsed!=="\
3
+ import{failureHint,isAuthError,isCliFatalText,isRateLimited,isServerAiType,isUntrusted,maxTurnsReached,rateLimitWaitSeconds,tailForScan}from"./chunk-ZOOEH7ZE.js";import{detectAiClis}from"./chunk-DEVIQH5U.js";import{DEFAULT_CLAUDE_LAUNCHER,activeSlotPath,detectClaudeAutoSwitch,isClaudeAi,isUsableModelId,modelFitsRoute,resolveSpawnTarget,usesBedrock,wrapWithAutoSwitch}from"./chunk-NWABK3RZ.js";import{isForceOnly,killProcessTree,system32}from"./chunk-N2UVRM3Z.js";import{findExecutable,
4
+ isWindowsDriveAbsolute}from"./chunk-PMOUHEJQ.js";import"./chunk-5WGOHFAS.js";import{stripTerminalControls}from"./chunk-NHYMHCAT.js";import"./chunk-VSJBJXZO.js";import{spawnSync}from"child_process";import fs2 from"fs";import path2 from"path";import{spawn}from"child_process";import fs from"fs";import path from"path";var FINAL_REPORT_BEGIN="<<<AI_FINAL_REPORT>>>";var FINAL_REPORT_END="<<<END_AI_FINAL_REPORT>>>";var ClaudeStreamRenderer=class{constructor(now=()=>new Date){this.now=now}now;toolNames=new Map;toolCount=0;result={subtype:null,isError:null,numTurns:null,costUsd:null,durationMs:null,tokensIn:null,tokensOut:null,rateLimited:false,resetsAt:null,finalText:""};push(line){const trimmed=line.trim();if(trimmed==="")return[];let event;try{const parsed=JSON.parse(trimmed);if(parsed===null||typeof parsed!=="\
5
5
  object"||Array.isArray(parsed)){return[line]}event=parsed}catch{return[line]}switch(event["type"]){case"rate_limit_event":return this.onRateLimit(event);case"assistant":return this.onAssistant(event);case"user":return this.onUser(event);case"result":return this.onResult(event);default:return event["type"]==="system"?[]:[line]}}sawRateLimit(){return this.result.rateLimited}lastRateLimitNote="";onRateLimit(event){const info=event["rate_limit_info"];if(info===null||typeof info!=="object")return[];const rec=info;
6
6
  const status=typeof rec["status"]==="string"?rec["status"]:"";const resets=typeof rec["resetsAt"]==="number"?rec["resetsAt"]:null;if(status==="")return[];const at=isSaneEpochSec(resets)?` resets=${new Date(resets*1e3).toISOString()}`:"";if(status.startsWith("allowed")){if(status==="allowed")return[];const seen=`${status}|${resets??""}`;if(seen===this.lastRateLimitNote)return[];this.lastRateLimitNote=seen;return[this.line(`\u2139\uFE0F \u4E0A\u9650\u306B\u63A5\u8FD1\uFF08status=${status}${at}\uFF09\u2014 \u5B9F\
7
7
  \u884C\u306F\u7D99\u7D9A\u3057\u307E\u3059`)]}if(resets!==null)this.result.resetsAt=resets;this.result.rateLimited=true;return[this.line(`\u26A0\uFE0F \u30EC\u30FC\u30C8\u30EA\u30DF\u30C3\u30C8\u901A\u77E5: status=${status}${at}`)]}onAssistant(event){const out=[];for(const block of contentBlocks(event)){if(block.type==="tool_use"){const name=typeof block.name==="string"?block.name:"tool";if(typeof block.id==="string")this.toolNames.set(block.id,name);this.toolCount+=1;out.push(this.line(`>> ${name}${toolDetail(
@@ -1,8 +1,8 @@
1
1
  import { createRequire as __twpCreateRequire } from 'node:module';
2
2
  const require = __twpCreateRequire(import.meta.url);
3
- import{readBody}from"./chunk-QVXZEUKN.js";import{OUTPUT_FORMATS,evaluateQuery,exitCodeFor,fetchAllPages,redactSecretValues,renderOutput,reportError,resolveOutputFormat,withDebug}from"./chunk-77CQG7O7.js";import"./chunk-WVS4W5FY.js";import{AuthSession,NotLoggedInError,SessionExpiredError,loadCredentials}from"./chunk-63LDNYGW.js";import{GLOBAL_OPTIONS_HELP,HELP_TOKEN}from"./chunk-FKIZ5ZJU.js";import{parseOperationArgs,repeatedValues}from"./chunk-O52CUEDO.js";import"./chunk-QQRJLH6B.js";
4
- import"./chunk-7WEYBZSK.js";import{ApiError,TwpApiClient,appendQuery}from"./chunk-JKSXUBND.js";import"./chunk-II5RVJQN.js";import{effectiveApiUrl,resolveConfiguredOutput,resolveProfile}from"./chunk-NERYSBA4.js";import"./chunk-RZVI6PMW.js";import{httpFetch}from"./chunk-J7QYPKVK.js";import{stripTerminalControls}from"./chunk-NHYMHCAT.js";import{DEFAULT_MAX_ITEMS,DEFAULT_MAX_PAGES,envelopePaging,positiveInteger,readEnvelopeCursor,shellQuote}from"./chunk-2VISRLWS.js";
5
- import{EXIT_OK,NetworkError,UsageError}from"./chunk-M3GWY6NT.js";import"./chunk-5QCAIKFE.js";import"./chunk-VSJBJXZO.js";import{readFile}from"fs/promises";import{existsSync}from"fs";import{dirname,join,resolve}from"path";import{fileURLToPath}from"url";var DIR_NAME="command-model";var cachedDir;function commandModelDir(){if(cachedDir!==void 0)return cachedDir;let current=dirname(fileURLToPath(import.meta.url));for(let depth=0;depth<6;depth+=1){const candidate=join(current,DIR_NAME);if(existsSync(join(candidate,"index.json"))){cachedDir=candidate;return cachedDir}if(existsSync(join(current,"package.json")))break;const parent=resolve(
3
+ import{NO_REDACT_FLAG,NO_REDACT_NOTICE,OUTPUT_FORMATS,evaluateQuery,exitCodeFor,fetchAllPages,redactSecretValues,renderOutput,reportError,resolveOutputFormat,withDebug}from"./chunk-SPZO6C5N.js";import"./chunk-WVS4W5FY.js";import{parseOperationArgs,repeatedValues}from"./chunk-O52CUEDO.js";import{GLOBAL_OPTIONS_HELP}from"./chunk-TAN5I2DP.js";import{HELP_TOKEN}from"./chunk-ZGG7TRAM.js";import"./chunk-QQRJLH6B.js";import{AuthSession,NotLoggedInError,SessionExpiredError,
4
+ loadCredentials}from"./chunk-XNLIEUAW.js";import{readBody}from"./chunk-QVXZEUKN.js";import"./chunk-MIMDLO52.js";import"./chunk-II5RVJQN.js";import{ApiError,TwpApiClient,appendQuery}from"./chunk-JKSXUBND.js";import{httpFetch}from"./chunk-J7QYPKVK.js";import{effectiveApiUrl,resolveConfiguredOutput,resolveProfile}from"./chunk-NERYSBA4.js";import"./chunk-RZVI6PMW.js";import{stripTerminalControls}from"./chunk-NHYMHCAT.js";import{DEFAULT_MAX_ITEMS,
5
+ DEFAULT_MAX_PAGES,envelopePaging,positiveInteger,readEnvelopeCursor,shellQuote}from"./chunk-2VISRLWS.js";import{EXIT_OK,NetworkError,UsageError}from"./chunk-M3GWY6NT.js";import"./chunk-5QCAIKFE.js";import"./chunk-VSJBJXZO.js";import{readFile}from"fs/promises";import{existsSync}from"fs";import{dirname,join,resolve}from"path";import{fileURLToPath}from"url";var DIR_NAME="command-model";var cachedDir;function commandModelDir(){if(cachedDir!==void 0)return cachedDir;let current=dirname(fileURLToPath(import.meta.url));for(let depth=0;depth<6;depth+=1){const candidate=join(current,DIR_NAME);if(existsSync(join(candidate,"index.json"))){cachedDir=candidate;return cachedDir}if(existsSync(join(current,"package.json")))break;const parent=resolve(
6
6
  current,"..");if(parent===current)break;current=parent}cachedDir=null;return cachedDir}var CommandModelMissingError=class extends Error{constructor(detail){super(`\u30B3\u30DE\u30F3\u30C9\u30E2\u30C7\u30EB\uFF08${DIR_NAME}/\uFF09\u3092\u8AAD\u3081\u307E\u305B\u3093: ${detail}
7
7
  \u958B\u767A\u6642\u306F \`npm run generate:command-model -- --spec <api.json>\` \u3067\u751F\u6210\u3057\u3066\u304F\u3060\u3055\u3044\u3002`);this.name="CommandModelMissingError"}};var domainCache=new Map;var routesCache=null;async function readJson(file){const dir=commandModelDir();if(dir===null)throw new CommandModelMissingError("\u30D1\u30C3\u30B1\u30FC\u30B8\u306B\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u304C\u3042\u308A\u307E\u305B\u3093");const path=join(dir,file);try{return JSON.parse(await readFile(path,"utf8"))}catch(cause){throw new CommandModelMissingError(`${path} \u3092\u8AAD\u3081\u307E\u305B\u3093\uFF08${cause.message}\uFF09`)}}async function loadCommandModelRoutes(){if(routesCache!==null)return routesCache;const file=await readJson("_routes.json");if(typeof file?.routes!=="object"||file.routes===null||Array.isArray(file.routes)){throw new CommandModelMissingError("_routes.json \u306E\u5F62\u304C\u9055\u3044\u307E\u3059\uFF08routes \u304C\u8AAD\u3081\u307E\u305B\u3093\uFF09")}routesCache=file;return routesCache}async function loadCommandModelDomain(domain){const cached=domainCache.get(domain);if(cached!==void 0)return cached;
8
8
  if(!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(domain)){throw new CommandModelMissingError(`\u30C9\u30E1\u30A4\u30F3\u540D\u3068\u3057\u3066\u4E0D\u6B63\u3067\u3059: ${domain}`)}const file=await readJson(`${domain}.json`);if(typeof file?.domain!=="string"||!Array.isArray(file?.operations)){throw new CommandModelMissingError(`${domain}.json \u306E\u5F62\u304C\u9055\u3044\u307E\u3059\uFF08domain / operations \u304C\u8AAD\u3081\u307E\u305B\u3093\uFF09`)}domainCache.set(domain,file);return file}var MIN_SEGMENT_CHARS=3;var parsedCache=new WeakMap;function splitSegments(path){return path.split("/").filter(segment=>segment!=="")}function parseRoutes(routes){const cached=parsedCache.get(routes);if(cached!==void 0)return cached;const parsed=[];for(const[key,domain]of Object.entries(routes.routes)){const space=key.indexOf(" ");if(space<=0)continue;const template=key.slice(space+1);parsed.push({method:key.slice(0,space),template,domain,segments:splitSegments(template).map(segment=>/^\{[^/{}]+\}$/.
@@ -82,32 +82,32 @@ call(value,key))walk(child,value[key],`${at}.${key}`,out)}}}}function validateBo
82
82
  ${GLOBAL_OPTIONS_HELP}
83
83
  `;var writeOut=text=>void process.stdout.write(text);var writeErr=text=>void process.stderr.write(text);function line(text){return text===""?"":text.endsWith("\n")?text:`${text}
84
84
  `}var API_METHODS=["GET","POST","PUT","PATCH","DELETE"];var API_FLAGS=[{name:"--method",summary:`HTTP \u30E1\u30BD\u30C3\u30C9\uFF08${API_METHODS.join(" / ")}\u30FB\u65E2\u5B9A GET\uFF09`,takesValue:true,placeholder:"<\u30E1\u30BD\u30C3\u30C9>"},{name:"--body-file",summary:"\u30EA\u30AF\u30A8\u30B9\u30C8\u30DC\u30C7\u30A3\u306E JSON \u30D5\u30A1\u30A4\u30EB\uFF08- \u3067\u6A19\u6E96\u5165\u529B\uFF09",takesValue:true,placeholder:"<\u30D1\u30B9>"},{name:"--cli-input-json",summary:"\u5168\u5F15\u6570\u3092 JSON \u3067\u6E21\u3059\uFF08-\
85
- \u3067\u6A19\u6E96\u5165\u529B\uFF09",takesValue:true,placeholder:"<\u30D1\u30B9>"},{name:"--generate-cli-skeleton",summary:"--cli-input-json \u3078\u6E21\u3059\u5165\u529B\u3072\u306A\u5F62\u3092\u51FA\u529B\u3057\u3066\u7D42\u4E86\u3059\u308B",takesValue:false},{name:"--query-param",summary:"\u30AF\u30A8\u30EA\u5F15\u6570\uFF08k=v\u30FB\u8907\u6570\u6307\u5B9A\u53EF\uFF09",takesValue:true,placeholder:"<k=v>",repeatable:true},{name:"--no-redact",summary:"\u5FDC\u7B54\u306E\u4F0F\u5B57\u5316\u3092\u89E3\u9664\u3057\u3066\u751F\u306E\u5024\u3092\u51FA\u3059\uFF08\u9375\u306E\u53D7\u3051\u53D6\u308A\u7B49\uFF09",
86
- takesValue:false},{name:"--max-items",summary:`\u81EA\u52D5\u30DA\u30FC\u30B8\u30F3\u30B0\u306E\u4E0A\u9650\u4EF6\u6570\uFF08\u65E2\u5B9A ${DEFAULT_MAX_ITEMS}\u30FB\u8D85\u3048\u305F\u3089\u5168\u4EF6\u3067\u306F\u306A\u3044\u3068\u660E\u793A\u3057\u3066\u6B62\u307E\u308B\uFF09`,takesValue:true,placeholder:"<\u4EF6\u6570>"},{name:"--starting-token",summary:"\u3053\u306E\u30AB\u30FC\u30BD\u30EB\uFF08\u524D\u56DE\u306E next_cursor\uFF09\u304B\u3089\u53D6\u5F97\u3092\u59CB\u3081\u308B",takesValue:true,
87
- placeholder:"<\u30AB\u30FC\u30BD\u30EB>"},{name:"--no-paginate",summary:"\u81EA\u52D5\u30DA\u30FC\u30B8\u30F3\u30B0\u3092\u305B\u305A1\u30DA\u30FC\u30B8\u3060\u3051\u53D6\u5F97\u3059\u308B",takesValue:false},{name:"--no-validate",summary:"\u9001\u4FE1\u524D\u306E\u30B9\u30AD\u30FC\u30DE\u691C\u8A3C\u3092\u884C\u308F\u306A\u3044\uFF08\u691C\u8A3C\u304C\u8AA4\u3063\u3066\u62D2\u3080\u3068\u304D\u7528\uFF09",takesValue:false}];var API_PAGING_VOCABULARY={mode:"\u81EA\u52D5\u30DA\u30FC\u30B8\u30F3\u30B0",
88
- resumeFlag:"--starting-token",capAdvice:"--query-param limit=<\u4EF6\u6570> \u30671\u30DA\u30FC\u30B8\u306E\u4EF6\u6570\u3092\u5897\u3084\u3057\u3066\u5F80\u5FA9\u3092\u6E1B\u3089\u3059\u304B\u3001--max-items \u3092\u4E0A\u3052\u3066\u304F\u3060\u3055\u3044\u3002"};var ENVELOPE_ITEMS_KEY="items";var CURSOR_PARAM="cursor";var SUGGESTION_LIMIT=5;var MAX_BODY_CHARS=1e6;function normalizeApiPath(raw){const trimmed=raw.trim();if(trimmed==="")throw new UsageError("\u30D1\u30B9\u304C\u7A7A\u3067\u3059",
89
- "\u4F8B: twp api /v2/projects");if(/^https?:\/\//i.test(trimmed)){throw new UsageError(`\u30D1\u30B9\u306B URL \u306F\u6E21\u305B\u307E\u305B\u3093: ${trimmed}`,"\u63A5\u7D9A\u5148\u306F\u30D7\u30ED\u30D5\u30A1\u30A4\u30EB\u304C\u6C7A\u3081\u307E\u3059\u3002\u30D1\u30B9\u3060\u3051\u3092\u6E21\u3057\u3066\u304F\u3060\u3055\u3044\uFF08\u4F8B: /v2/projects\uFF09\u3002")}const hashIndex=trimmed.indexOf("#");const withoutHash=hashIndex===-1?trimmed:trimmed.slice(0,hashIndex);const queryIndex=withoutHash.
90
- indexOf("?");const pathPart=queryIndex===-1?withoutHash:withoutHash.slice(0,queryIndex);const queryPart=queryIndex===-1?void 0:withoutHash.slice(queryIndex+1);const withSlash=pathPart.startsWith("/")?pathPart:`/${pathPart}`;const path=withSlash.toLowerCase().startsWith("/api/")?withSlash:`/api${withSlash}`;return{path,query:queryPart===void 0||queryPart===""?void 0:queryPart}}function parseMethod(raw){if(raw===void 0)return"GET";const upper=raw.trim().toUpperCase();if(API_METHODS.includes(upper))
91
- return upper;throw new UsageError(`--method \u306B\u300C${raw}\u300D\u306F\u6307\u5B9A\u3067\u304D\u307E\u305B\u3093`,`\u6307\u5B9A\u3067\u304D\u308B\u306E\u306F ${API_METHODS.join(" / ")} \u3067\u3059\u3002`)}function parseQueryParams(values){const out={};for(const raw of values){const index=raw.indexOf("=");if(index<=0){throw new UsageError(`--query-param \u306F k=v \u306E\u5F62\u3067\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044: ${raw}`,"\u4F8B: --query-param limit=10 --query-param keyword=\u4F1A\u8B70")}
92
- const key=raw.slice(0,index);if(Object.prototype.hasOwnProperty.call(out,key)){throw new UsageError(`--query-param ${key} \u304C\u8907\u6570\u56DE\u6307\u5B9A\u3055\u308C\u3066\u3044\u307E\u3059`)}out[key]=raw.slice(index+1)}return out}function parseQueryString(raw){if(raw===void 0)return{};const out={};for(const[key,value]of new URLSearchParams(raw))out[key]=value;return out}function buildSkeleton(method,path,query){const skeleton={method,path};const queryEntries=Object.entries(query);skeleton.
93
- query=queryEntries.length>0?Object.fromEntries(queryEntries.map(([key,value])=>[key,String(value??"")])):{};if(method!=="GET")skeleton.body={};return skeleton}function parseCliInput(text){let parsed;try{parsed=JSON.parse(text)}catch(err){throw new UsageError(`--cli-input-json \u306E JSON \u3092\u89E3\u91C8\u3067\u304D\u307E\u305B\u3093: ${err.message}`)}if(parsed===null||typeof parsed!=="object"||Array.isArray(parsed)){throw new UsageError("--cli-input-json \u306B\u306F\u30AA\u30D6\u30B8\u30A7\u30AF\u30C8\u3092\u6E21\u3057\u3066\u304F\u3060\u3055\u3044",
94
- '\u4F8B: {"method":"POST","path":"/v2/...","body":{}}')}const known=new Set(["method","path","query","body"]);const unknown=Object.keys(parsed).filter(key=>!known.has(key));if(unknown.length>0){throw new UsageError(`--cli-input-json \u306B\u77E5\u3089\u306A\u3044\u30AD\u30FC\u304C\u3042\u308A\u307E\u3059: ${unknown.join(" / ")}`,`\u4F7F\u3048\u308B\u306E\u306F ${[...known].join(" / ")} \u3067\u3059\u3002`)}const input=parsed;for(const key of["method","path"]){const value=input[key];if(value!==void 0&&
95
- typeof value!=="string"){throw new UsageError(`--cli-input-json \u306E ${key} \u306F\u6587\u5B57\u5217\u3067\u6E21\u3057\u3066\u304F\u3060\u3055\u3044`)}}if(input.query!==void 0){if(input.query===null||typeof input.query!=="object"||Array.isArray(input.query)){throw new UsageError("--cli-input-json \u306E query \u306F\u30AA\u30D6\u30B8\u30A7\u30AF\u30C8\u3067\u6E21\u3057\u3066\u304F\u3060\u3055\u3044")}for(const[key,value]of Object.entries(input.query)){if(typeof value!=="string"&&typeof value!==
96
- "number"&&typeof value!=="boolean"){throw new UsageError(`--cli-input-json \u306E query.${key} \u306F\u6587\u5B57\u5217\u30FB\u6570\u5024\u30FB\u771F\u507D\u5024\u3067\u6E21\u3057\u3066\u304F\u3060\u3055\u3044`)}}}return input}async function runApiCommand(options){const{globals}=options;let format=null;try{const profile=resolveProfile(globals.profile);format=resolveOutputFormat({...globals.output!==void 0?{flag:globals.output}:{},...(()=>{const configured=resolveConfiguredOutput(profile.name);return configured!==
97
- void 0?{configured}:{}})(),isTty:process.stdout.isTTY===true});if(format===null){throw new UsageError(`--output \u306B\u300C${globals.output??""}\u300D\u306F\u6307\u5B9A\u3067\u304D\u307E\u305B\u3093`,`\u6307\u5B9A\u3067\u304D\u308B\u306E\u306F ${OUTPUT_FORMATS.join(" / ")} \u3067\u3059`)}if(options.help||options.argv[0]===HELP_TOKEN){const extra=options.argv[0]===HELP_TOKEN?options.argv.slice(1):options.argv;if(extra.length>0&&!options.help){throw new UsageError(`twp api help \u306F\u5F15\u6570\u3092\u53D6\u308A\u307E\u305B\u3093: ${extra.
98
- join(" ")}`,"\u30D1\u30B9\u3092\u53E9\u304F\u306A\u3089 help \u3092\u5916\u3057\u3066\u304F\u3060\u3055\u3044\uFF08\u4F8B: twp api /v2/projects\uFF09\u3002")}writeOut(API_COMMAND_HELP);return EXIT_OK}const input=parseOperationArgs(options.argv,API_FLAGS);const noRedact=input.flags.has("--no-redact");const cliInputText=await readBody(input,{flag:"--cli-input-json-inline",fileFlag:"--cli-input-json",label:"--cli-input-json",maxChars:MAX_BODY_CHARS,usage:"\u4F8B: twp api /v2/projects --method POST --gen\
99
- erate-cli-skeleton > in.json"});const cliInput=cliInputText===void 0?void 0:parseCliInput(cliInputText);const[pathArg,...extraArgs]=input.args;if(extraArgs.length>0){throw new UsageError(`\u4F59\u5206\u306A\u5F15\u6570\u304C\u3042\u308A\u307E\u3059: ${extraArgs.join(" ")}`,"twp api \u304C\u53D7\u3051\u308B\u4F4D\u7F6E\u5F15\u6570\u306F\u30D1\u30B91\u3064\u3060\u3051\u3067\u3059\u3002\u30AF\u30A8\u30EA\u306F\u30D1\u30B9\u306B\u66F8\u304F\u304B --query-param \u3067\u6E21\u3057\u3066\u304F\u3060\u3055\u3044\u3002")}
100
- const rawPath=pathArg??cliInput?.path;if(rawPath===void 0){throw new UsageError("\u30D1\u30B9\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044","\u4F8B: twp api /v2/projects?limit=10\uFF08\u4E00\u89A7\u306F twp api help\uFF09")}const{path,query:inlineQuery}=normalizeApiPath(rawPath);const method=parseMethod(input.flags.get("--method")??cliInput?.method);const query={...parseQueryString(inlineQuery),...cliInput?.query??{},...parseQueryParams(repeatedValues(input,"--query-param"))};if(input.flags.
101
- has("--generate-cli-skeleton")){if(input.flags.has("--body-file")){throw new UsageError("--generate-cli-skeleton \u3068 --body-file \u306F\u540C\u6642\u306B\u6307\u5B9A\u3067\u304D\u307E\u305B\u3093","\u3072\u306A\u5F62\u3092\u51FA\u3057\u3066\u304B\u3089\u7DE8\u96C6\u3057\u3001--cli-input-json \u3067\u6E21\u3057\u3066\u304F\u3060\u3055\u3044\u3002")}writeOut(`${JSON.stringify(buildSkeleton(method,path.replace(/^\/api/,""),query),null,2)}
85
+ \u3067\u6A19\u6E96\u5165\u529B\uFF09",takesValue:true,placeholder:"<\u30D1\u30B9>"},{name:"--generate-cli-skeleton",summary:"--cli-input-json \u3078\u6E21\u3059\u5165\u529B\u3072\u306A\u5F62\u3092\u51FA\u529B\u3057\u3066\u7D42\u4E86\u3059\u308B",takesValue:false},{name:"--query-param",summary:"\u30AF\u30A8\u30EA\u5F15\u6570\uFF08k=v\u30FB\u8907\u6570\u6307\u5B9A\u53EF\uFF09",takesValue:true,placeholder:"<k=v>",repeatable:true},NO_REDACT_FLAG,{name:"--max-items",summary:`\u81EA\u52D5\u30DA\u30FC\u30B8\u30F3\u30B0\u306E\u4E0A\u9650\u4EF6\u6570\uFF08\u65E2\u5B9A ${DEFAULT_MAX_ITEMS}\
86
+ \u30FB\u8D85\u3048\u305F\u3089\u5168\u4EF6\u3067\u306F\u306A\u3044\u3068\u660E\u793A\u3057\u3066\u6B62\u307E\u308B\uFF09`,takesValue:true,placeholder:"<\u4EF6\u6570>"},{name:"--starting-token",summary:"\u3053\u306E\u30AB\u30FC\u30BD\u30EB\uFF08\u524D\u56DE\u306E next_cursor\uFF09\u304B\u3089\u53D6\u5F97\u3092\u59CB\u3081\u308B",takesValue:true,placeholder:"<\u30AB\u30FC\u30BD\u30EB>"},{name:"--no-paginate",summary:"\u81EA\u52D5\u30DA\u30FC\u30B8\u30F3\u30B0\u3092\u305B\u305A1\u30DA\u30FC\u30B8\u3060\u3051\u53D6\u5F97\u3059\u308B",
87
+ takesValue:false},{name:"--no-validate",summary:"\u9001\u4FE1\u524D\u306E\u30B9\u30AD\u30FC\u30DE\u691C\u8A3C\u3092\u884C\u308F\u306A\u3044\uFF08\u691C\u8A3C\u304C\u8AA4\u3063\u3066\u62D2\u3080\u3068\u304D\u7528\uFF09",takesValue:false}];var API_PAGING_VOCABULARY={mode:"\u81EA\u52D5\u30DA\u30FC\u30B8\u30F3\u30B0",resumeFlag:"--starting-token",capAdvice:"--query-param limit=<\u4EF6\u6570> \u30671\u30DA\u30FC\u30B8\u306E\u4EF6\u6570\u3092\u5897\u3084\u3057\u3066\u5F80\u5FA9\u3092\u6E1B\u3089\u3059\u304B\u3001--max-items \u3092\u4E0A\u3052\u3066\u304F\u3060\u3055\u3044\u3002"};
88
+ var ENVELOPE_ITEMS_KEY="items";var CURSOR_PARAM="cursor";var SUGGESTION_LIMIT=5;var MAX_BODY_CHARS=1e6;function normalizeApiPath(raw){const trimmed=raw.trim();if(trimmed==="")throw new UsageError("\u30D1\u30B9\u304C\u7A7A\u3067\u3059","\u4F8B: twp api /v2/projects");if(/^https?:\/\//i.test(trimmed)){throw new UsageError(`\u30D1\u30B9\u306B URL \u306F\u6E21\u305B\u307E\u305B\u3093: ${trimmed}`,"\u63A5\u7D9A\u5148\u306F\u30D7\u30ED\u30D5\u30A1\u30A4\u30EB\u304C\u6C7A\u3081\u307E\u3059\u3002\u30D1\u30B9\u3060\u3051\u3092\u6E21\u3057\u3066\u304F\u3060\u3055\u3044\uFF08\u4F8B: /v2/projects\uFF09\u3002")}
89
+ const hashIndex=trimmed.indexOf("#");const withoutHash=hashIndex===-1?trimmed:trimmed.slice(0,hashIndex);const queryIndex=withoutHash.indexOf("?");const pathPart=queryIndex===-1?withoutHash:withoutHash.slice(0,queryIndex);const queryPart=queryIndex===-1?void 0:withoutHash.slice(queryIndex+1);const withSlash=pathPart.startsWith("/")?pathPart:`/${pathPart}`;const path=withSlash.toLowerCase().startsWith("/api/")?withSlash:`/api${withSlash}`;return{path,query:queryPart===void 0||queryPart===""?void 0:
90
+ queryPart}}function parseMethod(raw){if(raw===void 0)return"GET";const upper=raw.trim().toUpperCase();if(API_METHODS.includes(upper))return upper;throw new UsageError(`--method \u306B\u300C${raw}\u300D\u306F\u6307\u5B9A\u3067\u304D\u307E\u305B\u3093`,`\u6307\u5B9A\u3067\u304D\u308B\u306E\u306F ${API_METHODS.join(" / ")} \u3067\u3059\u3002`)}function parseQueryParams(values){const out={};for(const raw of values){const index=raw.indexOf("=");if(index<=0){throw new UsageError(`--query-param \u306F k=v \u306E\
91
+ \u5F62\u3067\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044: ${raw}`,"\u4F8B: --query-param limit=10 --query-param keyword=\u4F1A\u8B70")}const key=raw.slice(0,index);if(Object.prototype.hasOwnProperty.call(out,key)){throw new UsageError(`--query-param ${key} \u304C\u8907\u6570\u56DE\u6307\u5B9A\u3055\u308C\u3066\u3044\u307E\u3059`)}out[key]=raw.slice(index+1)}return out}function parseQueryString(raw){if(raw===void 0)return{};const out={};for(const[key,value]of new URLSearchParams(raw))out[key]=
92
+ value;return out}function buildSkeleton(method,path,query){const skeleton={method,path};const queryEntries=Object.entries(query);skeleton.query=queryEntries.length>0?Object.fromEntries(queryEntries.map(([key,value])=>[key,String(value??"")])):{};if(method!=="GET")skeleton.body={};return skeleton}function parseCliInput(text){let parsed;try{parsed=JSON.parse(text)}catch(err){throw new UsageError(`--cli-input-json \u306E JSON \u3092\u89E3\u91C8\u3067\u304D\u307E\u305B\u3093: ${err.message}`)}if(parsed===
93
+ null||typeof parsed!=="object"||Array.isArray(parsed)){throw new UsageError("--cli-input-json \u306B\u306F\u30AA\u30D6\u30B8\u30A7\u30AF\u30C8\u3092\u6E21\u3057\u3066\u304F\u3060\u3055\u3044",'\u4F8B: {"method":"POST","path":"/v2/...","body":{}}')}const known=new Set(["method","path","query","body"]);const unknown=Object.keys(parsed).filter(key=>!known.has(key));if(unknown.length>0){throw new UsageError(`--cli-input-json \u306B\u77E5\u3089\u306A\u3044\u30AD\u30FC\u304C\u3042\u308A\u307E\u3059: ${unknown.
94
+ join(" / ")}`,`\u4F7F\u3048\u308B\u306E\u306F ${[...known].join(" / ")} \u3067\u3059\u3002`)}const input=parsed;for(const key of["method","path"]){const value=input[key];if(value!==void 0&&typeof value!=="string"){throw new UsageError(`--cli-input-json \u306E ${key} \u306F\u6587\u5B57\u5217\u3067\u6E21\u3057\u3066\u304F\u3060\u3055\u3044`)}}if(input.query!==void 0){if(input.query===null||typeof input.query!=="object"||Array.isArray(input.query)){throw new UsageError("--cli-input-json \u306E query \u306F\u30AA\u30D6\
95
+ \u30B8\u30A7\u30AF\u30C8\u3067\u6E21\u3057\u3066\u304F\u3060\u3055\u3044")}for(const[key,value]of Object.entries(input.query)){if(typeof value!=="string"&&typeof value!=="number"&&typeof value!=="boolean"){throw new UsageError(`--cli-input-json \u306E query.${key} \u306F\u6587\u5B57\u5217\u30FB\u6570\u5024\u30FB\u771F\u507D\u5024\u3067\u6E21\u3057\u3066\u304F\u3060\u3055\u3044`)}}}return input}async function runApiCommand(options){const{globals}=options;let format=null;try{const profile=resolveProfile(
96
+ globals.profile);format=resolveOutputFormat({...globals.output!==void 0?{flag:globals.output}:{},...(()=>{const configured=resolveConfiguredOutput(profile.name);return configured!==void 0?{configured}:{}})(),isTty:process.stdout.isTTY===true});if(format===null){throw new UsageError(`--output \u306B\u300C${globals.output??""}\u300D\u306F\u6307\u5B9A\u3067\u304D\u307E\u305B\u3093`,`\u6307\u5B9A\u3067\u304D\u308B\u306E\u306F ${OUTPUT_FORMATS.join(" / ")} \u3067\u3059`)}if(options.help||options.argv[0]===
97
+ HELP_TOKEN){const extra=options.argv[0]===HELP_TOKEN?options.argv.slice(1):options.argv;if(extra.length>0&&!options.help){throw new UsageError(`twp api help \u306F\u5F15\u6570\u3092\u53D6\u308A\u307E\u305B\u3093: ${extra.join(" ")}`,"\u30D1\u30B9\u3092\u53E9\u304F\u306A\u3089 help \u3092\u5916\u3057\u3066\u304F\u3060\u3055\u3044\uFF08\u4F8B: twp api /v2/projects\uFF09\u3002")}writeOut(API_COMMAND_HELP);return EXIT_OK}const input=parseOperationArgs(options.argv,API_FLAGS);const noRedact=input.flags.
98
+ has("--no-redact");const cliInputText=await readBody(input,{flag:"--cli-input-json-inline",fileFlag:"--cli-input-json",label:"--cli-input-json",maxChars:MAX_BODY_CHARS,usage:"\u4F8B: twp api /v2/projects --method POST --generate-cli-skeleton > in.json"});const cliInput=cliInputText===void 0?void 0:parseCliInput(cliInputText);const[pathArg,...extraArgs]=input.args;if(extraArgs.length>0){throw new UsageError(`\u4F59\u5206\u306A\u5F15\u6570\u304C\u3042\u308A\u307E\u3059: ${extraArgs.join(" ")}`,"tw\
99
+ p api \u304C\u53D7\u3051\u308B\u4F4D\u7F6E\u5F15\u6570\u306F\u30D1\u30B91\u3064\u3060\u3051\u3067\u3059\u3002\u30AF\u30A8\u30EA\u306F\u30D1\u30B9\u306B\u66F8\u304F\u304B --query-param \u3067\u6E21\u3057\u3066\u304F\u3060\u3055\u3044\u3002")}const rawPath=pathArg??cliInput?.path;if(rawPath===void 0){throw new UsageError("\u30D1\u30B9\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044","\u4F8B: twp api /v2/projects?limit=10\uFF08\u4E00\u89A7\u306F twp api help\uFF09")}const{path,query:inlineQuery}=normalizeApiPath(
100
+ rawPath);const method=parseMethod(input.flags.get("--method")??cliInput?.method);const query={...parseQueryString(inlineQuery),...cliInput?.query??{},...parseQueryParams(repeatedValues(input,"--query-param"))};if(input.flags.has("--generate-cli-skeleton")){if(input.flags.has("--body-file")){throw new UsageError("--generate-cli-skeleton \u3068 --body-file \u306F\u540C\u6642\u306B\u6307\u5B9A\u3067\u304D\u307E\u305B\u3093","\u3072\u306A\u5F62\u3092\u51FA\u3057\u3066\u304B\u3089\u7DE8\u96C6\u3057\u3001--cli-input-json \u3067\u6E21\u3057\u3066\u304F\u3060\u3055\u3044\u3002")}
101
+ writeOut(`${JSON.stringify(buildSkeleton(method,path.replace(/^\/api/,""),query),null,2)}
102
102
  `);return EXIT_OK}const bodyText=await readBody(input,{flag:"--body-inline",fileFlag:"--body-file",label:"\u30EA\u30AF\u30A8\u30B9\u30C8\u30DC\u30C7\u30A3",maxChars:MAX_BODY_CHARS,usage:"\u4F8B: twp api /v2/projects --method POST --body-file body.json --yes"});let body;if(bodyText!==void 0){try{body=JSON.parse(bodyText)}catch(err){throw new UsageError(`--body-file \u306E JSON \u3092\u89E3\u91C8\u3067\u304D\u307E\u305B\u3093: ${err.message}`)}}else if(cliInput!==void 0&&"body"in cliInput){body=cliInput.
103
103
  body}if(body!==void 0&&method==="GET"){throw new UsageError("GET \u306B\u30EA\u30AF\u30A8\u30B9\u30C8\u30DC\u30C7\u30A3\u306F\u4ED8\u3051\u3089\u308C\u307E\u305B\u3093","\u66F8\u304D\u8FBC\u307F\u306A\u3089 --method POST / PUT / PATCH \u3092\u3001\u7D5E\u308A\u8FBC\u307F\u306A\u3089 --query-param \u3092\u4F7F\u3063\u3066\u304F\u3060\u3055\u3044\u3002")}if(!globals.dryRun&&method!=="GET"&&!globals.yes){throw new UsageError(`twp api \u306F GET \u4EE5\u5916\u306B --yes \u304C\u5FC5\u8981\u3067\u3059\uFF08\u6307\u5B9A: ${method}\
104
104
  ${path}\uFF09`,"\u9001\u308B\u5185\u5BB9\u306F --dry-run \u3067\u5148\u306B\u78BA\u8A8D\u3067\u304D\u307E\u3059\u3002")}const noValidate=input.flags.has("--no-validate");const model=await resolveModel(method,path);const paging=resolveApiPaging(input,model,method,query);if(paging.startingToken!==void 0)query[CURSOR_PARAM]=paging.startingToken;if(model.operation!==null&&!noValidate)assertValid(model.operation,query,body);const plan={method,path,query,...body!==void 0?{body}:{}};const stored=loadCredentials(
105
105
  profile.name);const apiUrl=effectiveApiUrl(profile,stored?.api_url);writeErr(`\u63A5\u7D9A\u5148: ${stripTerminalControls(profile.name)} (${stripTerminalControls(apiUrl)})
106
106
  `);for(const note of model.notes)writeErr(`${stripTerminalControls(note)}
107
- `);if(noValidate)writeErr("\u6CE8\u8A18: --no-validate \u306E\u305F\u3081\u9001\u4FE1\u524D\u306E\u30B9\u30AD\u30FC\u30DE\u691C\u8A3C\u3092\u884C\u3044\u307E\u305B\u3093\u3002\n");if(noRedact){writeErr("\u6CE8\u8A18: --no-redact \u306E\u305F\u3081\u51FA\u529B\u3092\u4F0F\u5B57\u5316\u3057\u307E\u305B\u3093\uFF08\u7AEF\u672B\u3068\u30ED\u30B0\u306B\u5E73\u6587\u3067\u6B8B\u308A\u307E\u3059\uFF09\u3002\n")}if(globals.dryRun){writeOut(line(renderOutput(dryRunValue(apiUrl,plan),format,noRedact)));return EXIT_OK}
108
- const transport=options.fetchImpl??httpFetch;const fetchImpl=globals.debug?withDebug(transport):transport;const session=new AuthSession(profile.name,apiUrl,process.env,fetchImpl);const client=new TwpApiClient(apiUrl,session,fetchImpl,options.version);let responseBody;try{responseBody=await client.request(plan.method,appendQuery(plan.path,plan.query),plan.body)}catch(err){if(err instanceof ApiError||err instanceof NotLoggedInError||err instanceof SessionExpiredError)throw err;throw new NetworkError(
109
- `${apiUrl} \u3078\u306E\u901A\u4FE1\u306B\u5931\u6557\u3057\u307E\u3057\u305F: ${err.message}`,{cause:err})}let paged;if(paging.resultPath!==null&&isPageable(responseBody,{...paging,resultPath:paging.resultPath})){paged=await fetchAllPages({client,apiUrl,plan,paging:envelopePaging({label:`${method} ${model.template??path}`,itemsKey:paging.resultPath,cursorParam:CURSOR_PARAM}),maxPages:DEFAULT_MAX_PAGES,maxItems:paging.maxItems,firstPage:responseBody,vocabulary:API_PAGING_VOCABULARY});responseBody=
110
- paged.body}const source=noRedact?responseBody:redactSecretValues(responseBody);const value=globals.query===void 0?source:await evaluateQuery(globals.query,source);writeOut(line(renderOutput(value,format,noRedact)));if(paged!==void 0&&paged.pages>1){writeErr(`\u81EA\u52D5\u30DA\u30FC\u30B8\u30F3\u30B0: ${paged.pages} \u30DA\u30FC\u30B8\u3092\u8FBF\u3063\u3066 ${paged.count} \u4EF6\u3092\u53D6\u5F97\u3057\u307E\u3057\u305F\u3002
107
+ `);if(noValidate)writeErr("\u6CE8\u8A18: --no-validate \u306E\u305F\u3081\u9001\u4FE1\u524D\u306E\u30B9\u30AD\u30FC\u30DE\u691C\u8A3C\u3092\u884C\u3044\u307E\u305B\u3093\u3002\n");if(noRedact){writeErr(`${NO_REDACT_NOTICE}
108
+ `)}if(globals.dryRun){writeOut(line(renderOutput(dryRunValue(apiUrl,plan),format,noRedact)));return EXIT_OK}const transport=options.fetchImpl??httpFetch;const fetchImpl=globals.debug?withDebug(transport):transport;const session=new AuthSession(profile.name,apiUrl,process.env,fetchImpl);const client=new TwpApiClient(apiUrl,session,fetchImpl,options.version);let responseBody;try{responseBody=await client.request(plan.method,appendQuery(plan.path,plan.query),plan.body)}catch(err){if(err instanceof ApiError||
109
+ err instanceof NotLoggedInError||err instanceof SessionExpiredError)throw err;throw new NetworkError(`${apiUrl} \u3078\u306E\u901A\u4FE1\u306B\u5931\u6557\u3057\u307E\u3057\u305F: ${err.message}`,{cause:err})}let paged;if(paging.resultPath!==null&&isPageable(responseBody,{...paging,resultPath:paging.resultPath})){paged=await fetchAllPages({client,apiUrl,plan,paging:envelopePaging({label:`${method} ${model.template??path}`,itemsKey:paging.resultPath,cursorParam:CURSOR_PARAM}),maxPages:DEFAULT_MAX_PAGES,
110
+ maxItems:paging.maxItems,firstPage:responseBody,vocabulary:API_PAGING_VOCABULARY});responseBody=paged.body}const source=noRedact?responseBody:redactSecretValues(responseBody);const value=globals.query===void 0?source:await evaluateQuery(globals.query,source);writeOut(line(renderOutput(value,format,noRedact)));if(paged!==void 0&&paged.pages>1){writeErr(`\u81EA\u52D5\u30DA\u30FC\u30B8\u30F3\u30B0: ${paged.pages} \u30DA\u30FC\u30B8\u3092\u8FBF\u3063\u3066 ${paged.count} \u4EF6\u3092\u53D6\u5F97\u3057\u307E\u3057\u305F\u3002
111
111
  `)}if(paged===void 0&&method==="GET"){const note=continuationNote(responseBody,paging);if(note!==null)writeErr(`${stripTerminalControls(note)}
112
112
  `)}return EXIT_OK}catch(err){const code=exitCodeFor(err);reportError(err,format,code);return code}}function dryRunValue(apiUrl,plan){const value={method:plan.method,url:`${apiUrl}${appendQuery(plan.path,plan.query)}`};if(plan.body!==void 0)value["body"]=plan.body;return value}var NOT_APPLIED="\u30B9\u30AD\u30FC\u30DE\u691C\u8A3C\u3068\u81EA\u52D5\u30DA\u30FC\u30B8\u30F3\u30B0\u306F\u884C\u3044\u307E\u305B\u3093\u3002";async function resolveModel(method,path){const modelPath=path.replace(/^\/api(?=\/)/i,
113
113
  "");try{const routes=await loadCommandModelRoutes();const found=lookupRoute(routes,method,modelPath);if(found.kind==="matched"){const operation=pickOperation((await loadCommandModelDomain(found.domain)).operations,method,found.template);if(operation!==null)return{operation,unmatched:null,template:found.template,notes:[]};return{operation:null,unmatched:"\u30B3\u30DE\u30F3\u30C9\u30E2\u30C7\u30EB\u306E\u7D22\u5F15\u3068\u5B9A\u7FA9\u304C\u98DF\u3044\u9055\u3063\u3066\u3044\u308B\u305F\u3081",template:null,