arkor login、arkor logout、arkor whoami
~/.arkor/credentials.json を読み書きするだけの 3 つの短いコマンドです。いずれも .arkor/state.json には触りません。匿名ワークスペースでは、初回 trainer.start()(または初回推論呼び出し)でランタイムがプロジェクトルーティングを自動作成します。OAuth ワークスペースでは学習の前に .arkor/state.json が存在している必要があります。今のところ arkor login も arkor init もこれを作らないので、現実的なパスは { orgSlug, projectSlug, projectId } を手で書くことです。状態ファイルが無くてランタイムがエラーを返すと、このフォールバックを案内します。
arkor login
--oauth を渡したときだけです。
概要
オプション
| フラグ | 説明 |
|---|---|
--oauth | ピッカーをスキップして Arkor Cloud の OAuth(Authorization Code + PKCE)フローを直接走らせる。--anonymous と排他。process.env.CI が立っていると --oauth needs a browser callback that CI runners can't complete. Use --anonymous in CI.(CI ランナーが完了できないブラウザーコールバックを --oauth は必要とする。CI では --anonymous を使ってください)で失敗します。PKCE はブラウザーコールバックを必要とするため、CI ではループバックが永遠にハングするからです。 |
--anonymous | ピッカーをスキップして使い捨ての匿名トークンを要求。--oauth と排他。これは arkor dev の起動時に認証情報がディスクに無いときに走るのと同じパスです。arkor dev は必ずまず匿名でブートストラップします。 |
--no-browser | 自動の open(url) 呼び出しを無効化。authorization URL はいずれにせよ表示されます(Browser: <url>(ブラウザー: <url>)行)。このフラグは CLI がブラウザーを起動するのを止めるだけです。ヘッドレス環境(SSH、Docker)で便利。OAuth パスにのみ影響します。 |
何が起きるか
- CLI はクラウド API の
/v1/auth/cli/configを呼んでデプロイの OAuth 設定を読みます。 --anonymousが渡されたら、/v1/auth/anonymousから匿名トークンを要求し、mode: "anon"で~/.arkor/credentials.jsonに書きます。--oauthが渡された場合、ピッカーをスキップして直接 OAuth フローへ。- フラグが渡されない場合、対話ピッカー(
OAuth (browser)/Anonymous)を表示し Anonymous が事前選択されます。デフォルトを受け入れる(プロンプトがブロッキングしない非対話的な場面でも同様)と匿名パスが走り、OAuth を選ぶと OAuth フローが走ります。 - OAuth フローは PKCE ペアを生成し、クラウド API から提供されたコールバックポートのいずれかでループバック HTTP サーバーを起動し、authorize URL を開く(または表示する)、コールバックを待ちます。コードをトークンに交換する前に state を検証し、不一致は CSRF 防止のため Abort されます。得られた OAuth トークンは
mode: "auth0"で~/.arkor/credentials.jsonに書かれます。
finally ブロックで閉じられるので、login が失敗してもサーバーは残りません。
匿名モードを 1 段落で
匿名認証は、アカウントなしで Arkor を試すためのものです。学習、ジョブ、その他の作業は匿名トークンを介してローカルマシーンに紐づきます。あとで OAuth に切り替える(arkor login --oauth、またはピッカーから OAuth (browser) を選ぶ)と認証情報ファイルは差し替えられますが、作業は移行されません。匿名で学習したものを残したいなら、学習を始める前に arkor login --oauth を走らせてください。
匿名アカウントは設計上 単一端末専用 です。クラウド API は匿名ユーザーごとに latest_jti を保持しており、userAuth は受信した JWT の jti が一致しないリクエストをすべて拒否します。jti はトークンのローテーションでしか変わらないので、実際の発火タイミングは大きく 2 つに分かれます。今のところ CLI は匿名トークンの自動 refresh を実装していません(@arkor/cloud-api-client の getToken() 側で配線予定で、SDK ロードマップ に乗っています)。そのためクライアント側からのローテーションは起こらず、別マシーンにコピーした ~/.arkor/credentials.json も大抵しばらく動いてしまいます。失効するのは、発行ユーザーが明示的に新 identity を発行したとき(arkor login --anonymous が新しい jti でファイルを上書き)か、管理者がサーバー側でローテーションしたとき。そのタイミングで他のコピーは次の呼び出しから失敗します。自動 refresh が入ると、refresh のたびに latest_jti が即座に進むので、別端末(または同じマシーン上の古いバックアップ)に残った旧 jti のコピーは予告なく次の呼び出しで失敗するようになります。いずれにせよ、負けた側のクライアントは HTTP 401 / 409 を code: "anonymous_token_single_device" で受け取り、cli/main.ts がそれを実行可能なガイダンスとして整形します。匿名行そのものが削除された場合は code: "anonymous_account_not_found" も同じ仕組みで surface されます。リカバリー提案は デプロイ形態に応じて分岐 します。OAuth がサポートされているデプロイでは arkor login --oauth を案内して複数端末対応のアカウントへサインアップする経路を示し、匿名専用デプロイ(OAuth 未設定)では代わりに arkor login --anonymous を案内します。後者で --oauth を出すとそのコマンドはそのまま失敗するので、新規匿名 identity の発行が唯一のリカバリ手段になるためです。いずれのパスも、過去の匿名作業は移行されません。前のワークスペースには発行元の credentials ファイルからしか到達できません。
匿名発行時の出力
どちらの匿名パスでも、新しいanonymousId と「同じ id がセッションをまたいで Arkor Cloud がこのクライアントを認識するための識別子である」旨の説明を必ず surface します。ただし出力の形は入口によって異なります。arkor login(--anonymous フラグまたはピッカー → Anonymous)はスピナーの停止行として Anonymous id: <id> を出し、続けて「認証情報ファイル(credentialsPath()、Linux と macOS では通常 ~/.arkor/credentials.json)を保持していれば同じ identity を維持できる」旨の info 行を別行で出します。arkor dev の自動ブートストラップはスピナーを使わず、id と同じ説明を 1 本の info 行にまとめて出します。ピッカー → Anonymous のパスでは、さらに成功メッセージと並んで 1 行の warn(Anonymous sessions aren't guaranteed to persist — sign in with `arkor login --oauth` to tie future work to your Arkor Cloud account.、和訳: 匿名セッションは永続性が保証されないので、今後の作業を Arkor Cloud アカウントに紐付けたいなら arkor login --oauth でサインインしてください)が出るので、発行時点でアップグレードのヒントが見えます。明示的な --anonymous ショートカットでは /v1/auth/cli/config の取得をスキップしているため arkor login --oauth がそのデプロイで成功するかわからず、稀に存在する匿名専用デプロイで失敗するコマンドへユーザーを誘導しないよう、warn は意図的に抑制されます。
匿名発行のあらゆる入口で、単一端末の制約も別行の info として surface します。実際の文言は永続性ナッジと同じ oauthAvailable のゲーティング契約に従って分岐します。OAuth サポートのデプロイでは Note: anonymous accounts work on this machine only. Run `arkor login --oauth` to sign up for multi-device access.(和訳: 注意: 匿名アカウントはこのマシーンでのみ動作します。複数端末で使うには arkor login --oauth でサインアップしてください)が出ますが、匿名専用デプロイ、および /v1/auth/cli/config の取得を意図的にスキップする arkor login --anonymous の経路では、bare な Note: anonymous accounts work on this machine only. だけが出ます。失敗確実なコマンドへユーザーを誘導しないためです。arkor whoami も匿名 identity に対しては bare 版のみを stderr に出します。さらに stdout / stderr の両方が TTY のときに限るので、出力をリダイレクトしたとき(stdout が TTY でなくなる)や、stderr 出力をすべて警告扱いする CI ランナー(stderr が TTY でなくなる)では追加のテキストは出ません。あくまで UX のヒントであり、どの挙動もゲートしません。stdout 側の形(JSON.stringify(user, null, 2) で出される user オブジェクトの JSON と、org に所属していれば続けて 1 行の人間向け Orgs: <slug>, … 行)は note 追加前と変わりません。ただし Orgs: 行は JSON 本体の一部ではなく後ろに付くサマリ行なので、出力全体をそのまま jq のような厳密な JSON パーサーに通すのは避けてください。
arkor logout
~/.arkor/credentials.json を削除します。デフォルトでは確認プロンプトが出ます。
概要
オプション
| フラグ | 説明 |
|---|---|
-y, --yes | 確認プロンプトをスキップ。 |
振る舞い
- 認証情報ファイルが存在しなければ、CLI は
No credentials on file.(認証情報ファイルがありません)と出して終了。 - ユーザーがプロンプトを断ると
Aborted.(中止しました)と出して削除せずに終了。 arkor logoutは.arkor/state.jsonや.arkor/build/成果物には触りません。完全に最初からやり直すには.arkor/も手動で削除してください。
arkor whoami
/v1/me から現在の identity を表示し、到達できる org slug も並べます。
概要
出力
サインイン中ならuser オブジェクトを JSON として整形表示し、レスポンスに org が含まれていれば Orgs: <slug>, <slug>, …(org 一覧)を 1 行で出します。~/.arkor/credentials.json が無いときは Not signed in. Run \arkor login` or `arkor login —anonymous`.(サインインしていません。arkor loginまたはarkor login —anonymous` を実行してください)と出して終了します。
終了コード
0: サインイン中、identity を表示。0: 未サインイン、メッセージは情報用のみ。1: クラウド API が426 Upgrade Requiredを返した。CLI はアップグレードのヒント(と検出したパッケージマネージャ用のアップグレードコマンド)を表示し、process.exitCode = 1を立てて、arkorのシャットダウンフックの非推奨警告フラッシュが終了前に走るようにします。1: クラウド API が認証状態系の構造化code(anonymous_token_single_deviceまたはanonymous_account_not_found)を返した。cli/main.tsのトップレベルハンドラがそれを stderr 上の実行可能なメッセージへ整形します。具体的な文言は トークンの有効期限 を参照。1: それ以外の非 2xx(一過性の 5xx、未マップの 4xx など)。以前は「Failed to fetch /v1/me (<status>). Token may be expired.を stdout に出して終了コード0」でしたが、本リリースで撤廃しました。arkor whoamiはCloudApiErrorを投げ、bin.tsがerr.message(例:cloud-api 503)だけを stderr に出してから非ゼロで終了します。スタックトレースは未知のError形(実質 SDK のバグ)に限り出すので、通常の HTTP 失敗はラッパーのログを汚しません。
認証情報の保存場所
両モードとも同じファイル~/.arkor/credentials.json に書き、mode フィールドが "auth0" か "anon" でタグ付けされます。これにより CLI(と Studio サーバー)はどのパスを使うかわかります。レイアウト全体は プロジェクト構成 を参照。
トークンの有効期限
OAuth セッションでは、認証情報ファイルにアクセストークンと発行されたリフレッシュトークン、トークン交換が返したexpiresAt タイムスタンプを記録します。リフレッシュトークンは保存していますが、CLI は まだ 期限切れアクセストークンの自動リフレッシュをしません。これはロードマップ上です。
実用上の意味は次のとおりです。
-
期限切れまたは無効化されたトークンはクラウド API からの非 2xx として現れます。
arkor whoamiは汎用的な「Token may be expired」を出さなくなり、代わりに上流のcode(あれば)を持ったCloudApiErrorを投げ、cli/main.tsのトップレベルハンドラが既知 2 種の認証状態codeを実行可能なガイダンスへ整形します。整形前にmain()は/v1/auth/cli/configを best-effort で取得し、リカバリーヒントをデプロイ形態に揃えます。code: "anonymous_token_single_device":- OAuth サポートのデプロイ:
Anonymous credentials were rejected as single-device. Anonymous accounts only work on one machine. Sign up for an account that supports multiple devices: arkor login --oauth(終了コード1)。 - 匿名専用デプロイ:
Anonymous credentials were rejected as single-device. Anonymous accounts only work on one machine. This deployment does not advertise OAuth, so the only recovery is to mint a new anonymous identity (your previous workspace data cannot be recovered): arkor login --anonymous(終了コード1)。
- OAuth サポートのデプロイ:
code: "anonymous_account_not_found"も同様に分岐し、末尾はarkor login --oauthまたはarkor login --anonymousのいずれか。
codeを持たないエラー(およびCloudApiError以外の例外)はmain()から再 throw されます。bin.tsのトップレベルawait main(...)は try/catch で囲まれており、エラーの形で挙動を分けます。CloudApiErrorはerr.message(上流のerror本文、または本文が空のときのcloud-api <status>フォールバック)だけを出すので、通常の HTTP 失敗は 1 行で終わり、原因を切り分けやすくなります。それ以外のErrorはerr.stack ?? err.messageで出すので、本物の SDK バグはフレームが見えます。いずれの場合もprocess.exit(1)ではなくprocess.exitCode = 1を立てるので、main()のfinallyブロックの非推奨警告フラッシュ + テレメトリーシャットダウンは終了前にちゃんと走ります。明示的に catch しているのは、Node のデフォルトの unhandled rejection ハンドラがバンドル後の minified なコードフレームを出すのを避け、サポート対象の Node バージョン全体で stderr の flush を確定させるためでもあります。 -
OAuth セッションの直し方は
arkor login --oauthをもう一度走らせることです。フル PKCE フローを通って~/.arkor/credentials.jsonを新トークンで上書きします。
@arkor/cloud-api-client の getToken() 側にあり、SDK ロードマップに残っています。今日時点で匿名セッションが失敗し始めたら arkor login --anonymous で新しいものを発行してください(新しい anonymousId が発行されるので、実質的には別ワークスペースになります)。
よくあるエラー
| メッセージ | 場所 | 意味 | 対処 |
|---|---|---|---|
Pick one of --oauth / --anonymous, not both.(--oauth と --anonymous のどちらか一方だけ指定してください) | arkor login | モードフラグを両方渡した。 | どちらか一方にする。 |
--oauth needs a browser callback that CI runners can't complete. Use --anonymous in CI.(CI ランナーが完了できないブラウザーコールバックを --oauth は必要とする。CI では --anonymous を使ってください) | arkor login --oauth(process.env.CI が立つ環境) | PKCE はブラウザーからのループバックリダイレクトに依存し、CI ではこれを満たせない。 | CI では --anonymous を使う。ブラウザーに到達できるローカルのヘッドレスフロー(例: ... --no-browser | tee logs)では、その実行の間 CI を unset にする。 |
State mismatch — aborting to prevent CSRF(state の不一致のため CSRF 防止で中止しました) | arkor login --oauth | ループバックコールバックに返ってきた state が CLI の生成したものと一致しない。たいていは前回 login の古いタブをブラウザーが開いたケース。 | arkor login --oauth を再実行し、新規に開いたタブでフローを完了。 |
Auth0 did not return a refresh token. Make sure the Application has 'offline_access' scope enabled.(Auth0 がリフレッシュトークンを返しませんでした。Application で offline_access スコープを有効にしてください) | arkor login --oauth | OAuth のトークン交換は成功したがレスポンスに refresh_token が無く、CLI がアクセストークンの寿命を超えてセッションを保てない。たいていデプロイ側の設定ミス。 | OAuth(Auth0)アプリケーションで offline_access スコープを有効化してから arkor login --oauth を再実行。 |
No credentials on file.(認証情報ファイルがありません) | arkor logout | ~/.arkor/credentials.json が存在しない。削除対象なし。 | サインインしたいなら先に arkor login。 |
Not signed in. Run \arkor login` or `arkor login —anonymous`.(サインインしていません。arkor loginまたはarkor login —anonymous` を実行してください) | arkor whoami | 上と同じ条件を別コマンドから出している。 | 同じ対処。 |
Anonymous credentials were rejected as single-device. …(末尾は arkor login --oauth または arkor login --anonymous、デプロイ形態次第) | arkor whoami および認証付きの全コマンド | クラウド API が code: "anonymous_token_single_device" で拒否した(userAuth の jti チェックからの HTTP 401、または rotate-jti の CAS からの HTTP 409)。認証情報ファイルが別端末にコピーされたか、別のローカルプロセスがこのトークンを recovery window 内でローテートし越えた、のいずれか。 | メッセージ末尾のコマンドに従う: OAuth サポートのデプロイなら arkor login --oauth、匿名専用デプロイなら arkor login --anonymous。どちらも 新規 identity で、過去の匿名作業は移行できない。CLI は 1 で終了。 |
Your anonymous credentials are no longer valid. …(末尾は arkor login --oauth または arkor login --anonymous) | arkor whoami および認証付きの全コマンド | クラウド API が code: "anonymous_account_not_found" で拒否した(HTTP 401)。背後の anonymous_users 行が削除された(admin / cascade / 明示的な revoke)。 | 上と同じく、メッセージ末尾のデプロイ依存コマンドに従う。前の匿名ワークスペースは取り戻せない。CLI は 1 で終了。 |
cloud-api <status>(1 行、スタックなし) | arkor whoami および認証付きの全コマンド | 構造化された認証状態 code を持たない非 200 / 非 426 のクラウド API レスポンス(一過性の 5xx、未マップの 4xx など)。cli/main.ts が CloudApiError をそのまま再 throw し、bin.ts がスタックの最上位で catch して err.message(上流の error 本文、または本文が空のときの cloud-api <status> フォールバック)だけを表示した後、process.exitCode = 1 をセットする。スタックトレースは未知の Error 形(実質 SDK のバグ)に限り出す。 | メッセージをそのまま確認し、トランスポート / サーバー障害なら再試行。OAuth アクセストークンの期限切れなら arkor login --oauth を再実行。匿名トークンの期限切れなら arkor login --anonymous を再実行(新しい anonymousId で別ワークスペースになる)。 |
426 Upgrade Required(アップグレードヒント付き) | arkor whoami(および他のクラウド API 呼び出し) | デプロイがより新しい SDK バージョンを要求している。CLI は検出したパッケージマネージャ用のアップグレードコマンドを表示し、process.exitCode = 1 を立てる。 | arkor パッケージをアップグレードして再実行。 |