Add GitHub CLI login flow#26
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (4)
✅ Files skipped from review due to trivial changes (1)
🚧 Files skipped from review as they are similar to previous changes (3)
📝 WalkthroughWalkthroughGitHub デバイスコード認証、CLI トークン保存、 ChangesCLI 認証とスライド管理
Review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested labels
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
19ae87d to
ab94927
Compare
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (1)
spec/slidict/cli_spec.rb (1)
92-103: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win
Pending後の待機もこのテストで固定しておきたいです。このケースは 1 回
Pendingを返しているのにsleeper.sleep(1)を検証していないので、待機処理が消えてもテストが通ります。ポーリング退行を拾えるようにここも期待値に入れておくと安心です。修正例
- sleeper = double("sleeper", sleep: nil) + sleeper = double("sleeper") @@ + expect(sleeper).to receive(:sleep).with(1).once status = cli.run(["auth"])🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@spec/slidict/cli_spec.rb` around lines 92 - 103, The auth flow test around described_class.new and cli.run(["auth"]) is missing an assertion for the Pending backoff, so it would still pass if the polling sleep were removed. Update this spec to expect the injected sleeper double to receive sleep(1) during the pending-to-success path, alongside the existing token write expectation, so the polling behavior in cli.run and the auth client handling remains covered.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@lib/slidict/auth_client.rb`:
- Around line 39-40: `AuthClient` では `authorization_pending` と `slow_down` を同じ
`Pending` にまとめないよう修正してください。`AuthClient#...` の `response["error"]` 判定で
`slow_down` は別例外(または別の戻り値)に分け、`CLI#auth` 側でそれを rescue
して次回の待機時間を増やすバックオフ処理を入れてください。`authorization_pending` は従来どおり `Pending`
のままにし、`slow_down` だけポーリング間隔を伸ばせるようにしてください。
- Line 25: `AuthClient` の `verification_uri` フォールバックが文字列連結になっており、`base_url`
の末尾スラッシュやサブパスで不正な URL になる可能性があります。`AuthClient#initialize` 内の `verification_uri`
生成を、同クラスの `post_json` と同じ URL 解決方針に合わせて `URI.join`
ベースに置き換え、`SLIDICT_AUTH_BASE_URL` の値に依存せず安全に `cli/activate` を組み立てるよう修正してください。
In `@lib/slidict/cli.rb`:
- Around line 145-160: The `slidict auth` flow only rescues `AuthClient::Error`
and `KeyError`, so failures from `credentials.write_cli_token!` can still crash
with `SystemCallError`. Update the `Slidict::CLI` auth path to catch save-time
OS errors around `credentials.write_cli_token!`, convert them into a user-facing
`@output.puts "Error: ..."` message, and return `1` just like the existing auth
failures.
---
Nitpick comments:
In `@spec/slidict/cli_spec.rb`:
- Around line 92-103: The auth flow test around described_class.new and
cli.run(["auth"]) is missing an assertion for the Pending backoff, so it would
still pass if the polling sleep were removed. Update this spec to expect the
injected sleeper double to receive sleep(1) during the pending-to-success path,
alongside the existing token write expectation, so the polling behavior in
cli.run and the auth client handling remains covered.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 4eae52e1-a89a-4f8a-a27f-85f2ee2688f7
📒 Files selected for processing (6)
lib/slidict.rblib/slidict/auth_client.rblib/slidict/cli.rblib/slidict/credentials.rbspec/slidict/cli_spec.rbspec/slidict/credentials_spec.rb
| { | ||
| device_code: fetch!(response, "device_code"), | ||
| user_code: fetch!(response, "user_code"), | ||
| verification_uri: response["verification_uri"] || "#{base_url}/cli/activate", |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
verification_uri のフォールバック生成は URI.join を使った方が安全です。
"#{base_url}/cli/activate" だと、SLIDICT_AUTH_BASE_URL が末尾 / 付きやサブパス付きの値だった場合に //cli/activate や /api/cli/activate になり、同じクラス内の post_json が使っている URL 解決とズレます。
修正例
- verification_uri: response["verification_uri"] || "#{base_url}/cli/activate",
+ verification_uri: response["verification_uri"] || URI.join(base_url, "/cli/activate").to_s,🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@lib/slidict/auth_client.rb` at line 25, `AuthClient` の `verification_uri`
フォールバックが文字列連結になっており、`base_url` の末尾スラッシュやサブパスで不正な URL
になる可能性があります。`AuthClient#initialize` 内の `verification_uri` 生成を、同クラスの `post_json`
と同じ URL 解決方針に合わせて `URI.join` ベースに置き換え、`SLIDICT_AUTH_BASE_URL` の値に依存せず安全に
`cli/activate` を組み立てるよう修正してください。
| error = response["error"].to_s | ||
| raise Pending if %w[authorization_pending slow_down].include?(error) |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
slow_down を authorization_pending と同一視するとバックオフできません。
ここで両方とも Pending に潰しているため、CLI#auth 側は常に元の interval で再試行し続けます。レート制限に入ったケースでポーリング間隔を伸ばせず、認証完了前にタイムアウトしやすくなります。
修正の方向性
class AuthClient
Error = Class.new(StandardError)
Pending = Class.new(StandardError)
+ SlowDown = Class.new(StandardError)
@@
- raise Pending if %w[authorization_pending slow_down].include?(error)
+ raise Pending if error == "authorization_pending"
+ raise SlowDown if error == "slow_down"# CLI#auth 側で SlowDown を rescue して待機時間を増やす🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@lib/slidict/auth_client.rb` around lines 39 - 40, `AuthClient` では
`authorization_pending` と `slow_down` を同じ `Pending`
にまとめないよう修正してください。`AuthClient#...` の `response["error"]` 判定で `slow_down`
は別例外(または別の戻り値)に分け、`CLI#auth` 側でそれを rescue
して次回の待機時間を増やすバックオフ処理を入れてください。`authorization_pending` は従来どおり `Pending`
のままにし、`slow_down` だけポーリング間隔を伸ばせるようにしてください。
| token = client.poll_token(device_code: device[:device_code]) | ||
| path = credentials.write_cli_token!( | ||
| access_token: token.fetch("access_token"), | ||
| token_type: token.fetch("token_type", "Bearer"), | ||
| provider: token.fetch("provider", "github") | ||
| ) | ||
| @output.puts "4. Saved CLI access token to #{path}" | ||
| return 0 | ||
| rescue AuthClient::Pending | ||
| return login_expired if Time.now >= deadline | ||
|
|
||
| @sleeper.sleep(device[:interval]) | ||
| end | ||
| rescue AuthClient::Error, KeyError => e | ||
| @output.puts "Error: GitHub auth failed (#{e.message})" | ||
| 1 |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
認証情報の保存失敗が未処理で、slidict auth が例外終了します。
credentials.write_cli_token! は権限不足やディスクフルで SystemCallError を投げうるのに、このメソッドはそれを rescue していません。ネットワークは成功しても保存時にスタックトレースで落ちるので、ここもユーザー向けエラーに畳んで 1 を返したいです。
修正例
- rescue AuthClient::Error, KeyError => e
+ rescue AuthClient::Error, KeyError, SystemCallError => e
`@output.puts` "Error: GitHub auth failed (#{e.message})"
1
end📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| token = client.poll_token(device_code: device[:device_code]) | |
| path = credentials.write_cli_token!( | |
| access_token: token.fetch("access_token"), | |
| token_type: token.fetch("token_type", "Bearer"), | |
| provider: token.fetch("provider", "github") | |
| ) | |
| @output.puts "4. Saved CLI access token to #{path}" | |
| return 0 | |
| rescue AuthClient::Pending | |
| return login_expired if Time.now >= deadline | |
| @sleeper.sleep(device[:interval]) | |
| end | |
| rescue AuthClient::Error, KeyError => e | |
| @output.puts "Error: GitHub auth failed (#{e.message})" | |
| 1 | |
| token = client.poll_token(device_code: device[:device_code]) | |
| path = credentials.write_cli_token!( | |
| access_token: token.fetch("access_token"), | |
| token_type: token.fetch("token_type", "Bearer"), | |
| provider: token.fetch("provider", "github") | |
| ) | |
| `@output.puts` "4. Saved CLI access token to #{path}" | |
| return 0 | |
| rescue AuthClient::Pending | |
| return login_expired if Time.now >= deadline | |
| `@sleeper.sleep`(device[:interval]) | |
| end | |
| rescue AuthClient::Error, KeyError, SystemCallError => e | |
| `@output.puts` "Error: GitHub auth failed (#{e.message})" | |
| 1 |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@lib/slidict/cli.rb` around lines 145 - 160, The `slidict auth` flow only
rescues `AuthClient::Error` and `KeyError`, so failures from
`credentials.write_cli_token!` can still crash with `SystemCallError`. Update
the `Slidict::CLI` auth path to catch save-time OS errors around
`credentials.write_cli_token!`, convert them into a user-facing `@output.puts
"Error: ..."` message, and return `1` just like the existing auth failures.
Lets the CLI manage slides on slidict.io via the CLI access token saved by `slidict auth`: list/show existing slides, and create or edit drafts (slides API never allows publishing from the CLI). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The device token endpoint returns a non-2xx status with an authorization_pending/slow_down body while polling, so post_json must return that body instead of raising before poll_token can check it. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (1)
spec/slidict/credentials_spec.rb (1)
25-43: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win破損した認証ファイルの分岐も spec で固定しておきたいです。
lib/slidict/credentials.rbの Line 28-37 では、不正 JSON とkind不一致をnilに落としていますが、この spec ではその 2 分岐が未カバーです。壊れたcredentials.jsonで CLI が再び落ちる回帰を防ぐため、ここも追加しておくと安心です。🧪 追加イメージ
describe "`#read_cli_token`" do + it "returns nil for malformed JSON" do + Dir.mktmpdir do |dir| + path = File.join(dir, "slidict", "credentials.json") + File.write(path, "{") + credentials = described_class.new(path: path) + + expect(credentials.read_cli_token).to be_nil + end + end + + it "returns nil for non CLI token credentials" do + Dir.mktmpdir do |dir| + path = File.join(dir, "slidict", "credentials.json") + File.write(path, JSON.generate("kind" => "web_session", "access_token" => "cli-token")) + credentials = described_class.new(path: path) + + expect(credentials.read_cli_token).to be_nil + end + end +🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@spec/slidict/credentials_spec.rb` around lines 25 - 43, `Credentials#read_cli_token` の未カバー分岐を spec に追加し、不正な JSON と `kind` 不一致のときに `nil` を返す挙動を固定してください。`described_class.new` と `read_cli_token` を使い、壊れた `credentials.json` と期待外の `kind` をそれぞれ用意して、例外にならず `nil` になることを確認するテストを `#read_cli_token` の describe 内に追加してください。
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@lib/slidict/credentials.rb`:
- Around line 28-36: The read_cli_token method only rescues JSON::ParserError,
so File.read failures after File.exist? can still crash slidict slides with a
SystemCallError. Update read_cli_token in lib/slidict/credentials.rb to also
handle I/O-related exceptions from File.read, either by returning nil as an
unauthenticated state or converting them into the appropriate domain error,
while keeping the existing JSON parsing and token shape checks intact.
In `@lib/slidict/slides_command.rb`:
- Around line 40-45: The argument parsing logic is rejecting any value that
starts with “-”, so valid strings like `--body "- item"` and `--title "-draft"`
are being treated as missing. Update `fetch_value!`/the option parsing path in
`parse_list` and the related code around the body/title handling to only treat
known switch names as absent values, not all dash-prefixed strings. Keep the
`--page` integer validation separate in `parse_list` so page-specific checks
still reject invalid numbers without blocking legitimate text values.
- Around line 150-153: `read_body` の `File.read` で発生する `Errno::ENOENT` や
`Errno::EACCES` が `run` で拾われず CLI が異常終了する問題を修正してください。`SlidesCommand#read_body`
でファイル読み込み失敗を捕捉してユーザー向けのエラーメッセージに変換し、`SlidesCommand#run` 側で `ArgumentError` と同様に
exit 1 へ落とせるようにしてください。`read_body`、`run`、`options[:file]` の分岐を目印に実装してください。
---
Nitpick comments:
In `@spec/slidict/credentials_spec.rb`:
- Around line 25-43: `Credentials#read_cli_token` の未カバー分岐を spec に追加し、不正な JSON と
`kind` 不一致のときに `nil` を返す挙動を固定してください。`described_class.new` と `read_cli_token`
を使い、壊れた `credentials.json` と期待外の `kind` をそれぞれ用意して、例外にならず `nil` になることを確認するテストを
`#read_cli_token` の describe 内に追加してください。
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: b3ec8869-d4f8-4974-83fd-a308d9c222de
📒 Files selected for processing (12)
AGENTS.mdREADME.mdlib/slidict.rblib/slidict/auth_client.rblib/slidict/cli.rblib/slidict/credentials.rblib/slidict/slides_client.rblib/slidict/slides_command.rbspec/slidict/cli_spec.rbspec/slidict/credentials_spec.rbspec/slidict/slides_client_spec.rbspec/slidict/slides_command_spec.rb
✅ Files skipped from review due to trivial changes (3)
- AGENTS.md
- README.md
- lib/slidict.rb
| def read_cli_token | ||
| return nil unless File.exist?(@path) | ||
|
|
||
| data = JSON.parse(File.read(@path)) | ||
| return nil unless data["kind"] == "cli_access_token" && data["access_token"] | ||
|
|
||
| { access_token: data["access_token"], token_type: data.fetch("token_type", "Bearer") } | ||
| rescue JSON::ParserError | ||
| nil |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
認証ファイルの読み取り失敗が slidict slides を例外終了させます。
ここは JSON::ParserError しか rescue していないので、File.exist? 後の削除や権限エラーで File.read が SystemCallError を投げると、そのまま CLI が落ちます。少なくともこのメソッド内で I/O 失敗も吸収して、未認証扱いかドメインエラーへ変換した方が安全です。
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@lib/slidict/credentials.rb` around lines 28 - 36, The read_cli_token method
only rescues JSON::ParserError, so File.read failures after File.exist? can
still crash slidict slides with a SystemCallError. Update read_cli_token in
lib/slidict/credentials.rb to also handle I/O-related exceptions from File.read,
either by returning nil as an unauthenticated state or converting them into the
appropriate domain error, while keeping the existing JSON parsing and token
shape checks intact.
| def parse_list(args) | ||
| options = { subcommand: :list } | ||
| until args.empty? | ||
| case (arg = args.shift) | ||
| when "--page" then options[:page] = Integer(fetch_value!(args, arg)) | ||
| when "-h", "--help" then options[:help] = true |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
--body "- item" のような正当な値を未指定扱いしてしまいます。
Line 92 が先頭 - の値を一律で弾いているので、--body "- item" や --title "-draft" が通りません。既知のスイッチ名だけを未指定扱いにして、--page の正数チェックは Line 44 側で分けた方が安全です。
💡 修正イメージ
def parse_list(args)
options = { subcommand: :list }
until args.empty?
case (arg = args.shift)
- when "--page" then options[:page] = Integer(fetch_value!(args, arg))
+ when "--page"
+ page = Integer(fetch_value!(args, arg))
+ raise ArgumentError, "--page must be >= 1" if page < 1
+ options[:page] = page
when "-h", "--help" then options[:help] = true
else raise ArgumentError, "unknown option #{arg}"
end
end
options
@@
def fetch_value!(args, option)
value = args.shift
- raise ArgumentError, "#{option} requires a value" if value.nil? || value.start_with?("-")
+ known_switches = %w[--page --title --body --file --body-format --visibility -h --help]
+ raise ArgumentError, "#{option} requires a value" if value.nil? || known_switches.include?(value)
value
endAlso applies to: 90-95
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@lib/slidict/slides_command.rb` around lines 40 - 45, The argument parsing
logic is rejecting any value that starts with “-”, so valid strings like `--body
"- item"` and `--title "-draft"` are being treated as missing. Update
`fetch_value!`/the option parsing path in `parse_list` and the related code
around the body/title handling to only treat known switch names as absent
values, not all dash-prefixed strings. Keep the `--page` integer validation
separate in `parse_list` so page-specific checks still reject invalid numbers
without blocking legitimate text values.
| def read_body(options) | ||
| return File.read(options[:file]) if options[:file] | ||
|
|
||
| options[:body] |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
--file の読み取り失敗がそのまま異常終了になります。
Line 151 の File.read で Errno::ENOENT や Errno::EACCES が出ると、run は ArgumentError しか拾わないため、そのまま CLI が落ちます。ここはユーザー向けエラーに変換して exit 1 に寄せたいです。
💡 修正イメージ
def read_body(options)
- return File.read(options[:file]) if options[:file]
+ return File.read(options[:file]) if options[:file]
options[:body]
+ rescue SystemCallError => e
+ raise ArgumentError, "could not read #{options[:file]}: #{e.message}"
end📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| def read_body(options) | |
| return File.read(options[:file]) if options[:file] | |
| options[:body] | |
| def read_body(options) | |
| return File.read(options[:file]) if options[:file] | |
| options[:body] | |
| rescue SystemCallError => e | |
| raise ArgumentError, "could not read #{options[:file]}: #{e.message}" | |
| end |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@lib/slidict/slides_command.rb` around lines 150 - 153, `read_body` の
`File.read` で発生する `Errno::ENOENT` や `Errno::EACCES` が `run` で拾われず CLI
が異常終了する問題を修正してください。`SlidesCommand#read_body`
でファイル読み込み失敗を捕捉してユーザー向けのエラーメッセージに変換し、`SlidesCommand#run` 側で `ArgumentError` と同様に
exit 1 へ落とせるようにしてください。`read_body`、`run`、`options[:file]` の分岐を目印に実装してください。
Lets the main `slidict` command save the generated deck straight to slidict.io as a draft via --publish (create) or --slide-id (edit an existing draft), reusing SlidesClient/SlidesCommand. Adds a public SlidesCommand#publish entry point that skips argv parsing entirely, since the rendered body often starts with "---" (YAML frontmatter) which the CLI-style "looks like a flag" check would otherwise reject. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
chore: bump version to v0.2.0
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@lib/slidict/cli.rb`:
- Around line 202-203: `body_format_for` の正規化ルールと `MarkdownRenderer#render`
の判定条件が一致していません。`body_format_for` と `MarkdownRenderer#render`
の両方で同じ正規化結果を使うように統一し、`framework` の大小文字や表記ゆれでも `asciidoctor-revealjs`
の扱いが同じになるよう修正してください。`body_format_for`、`MarkdownRenderer#render`、および `framework`
の比較ロジックを合わせて、本文形式の決定と実際のレンダリング分岐が矛盾しないようにしてください。
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: e179354e-e833-49c1-af20-361d59ec1030
📒 Files selected for processing (5)
README.mdlib/slidict/cli.rblib/slidict/slides_command.rbspec/slidict/cli_spec.rbspec/slidict/slides_command_spec.rb
✅ Files skipped from review due to trivial changes (2)
- README.md
- spec/slidict/slides_command_spec.rb
🚧 Files skipped from review as they are similar to previous changes (1)
- lib/slidict/slides_command.rb
| def body_format_for(framework) | ||
| framework.to_s.downcase == "asciidoctor-revealjs" ? "asciidoc" : "markdown" |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
body_format と実際のレンダリング形式を同じ正規化ルールにしてください。
body_format_for は大小文字を無視しますが、MarkdownRenderer#render は "asciidoctor-revealjs" の完全一致で分岐します。--framework Asciidoctor-RevealJS のような入力では Markdown 本文を asciidoc として publish し得ます。
修正例
- options[:output] ||= default_output_for(options[:framework])
+ options[:framework] = options[:framework].to_s.downcase
+ options[:output] ||= default_output_for(options[:framework])
options🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@lib/slidict/cli.rb` around lines 202 - 203, `body_format_for` の正規化ルールと
`MarkdownRenderer#render` の判定条件が一致していません。`body_format_for` と
`MarkdownRenderer#render` の両方で同じ正規化結果を使うように統一し、`framework` の大小文字や表記ゆれでも
`asciidoctor-revealjs`
の扱いが同じになるよう修正してください。`body_format_for`、`MarkdownRenderer#render`、および `framework`
の比較ロジックを合わせて、本文形式の決定と実際のレンダリング分岐が矛盾しないようにしてください。
--publish (and `slidict slides create/edit`) used to fail with a bare "Error: invalid_token" or "not authenticated" message. Now SlidesCommand triggers the existing `slidict auth` device-login flow automatically and retries once when the token is missing or rejected by the API. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Reverts #25
Summary by CodeRabbit
slidict authを追加しました(GitHub デバイスコード方式で認証し、CLI用アクセストークンを保存)。slidict slidesを追加しました(list/show/create/edit に加え、--publishで下書き反映、--slide-idで下書き編集)。--publish、--slide-id、--slide-title、--visibility)の説明を追加しました。