From 52e4c674e2b09a51edc351f548382e0647a45e2f Mon Sep 17 00:00:00 2001 From: Abid Famasya Date: Fri, 13 Feb 2026 09:47:33 +0700 Subject: [PATCH 1/4] feat: add --comments flag to include Google Docs comments in markdown output Fetches comments via the Google Drive Comments API and appends them as a ## Comments section at the end of the markdown output. Includes quoted text, author, date, resolved status, and replies. - Add internal/gdocs/comments.go for fetching comments via Drive API - Add internal/markdown/comments.go for rendering comments as markdown - Add --comments CLI flag - Add drive.readonly OAuth scope - Add tests for comment rendering and time formatting - Update README with usage docs and scope requirements Closes #2 Amp-Thread-ID: https://ampcode.com/threads/T-019c54ce-f0ae-76e3-87fe-06b9a3e2c02f Co-authored-by: Amp --- .gitignore | 4 +- README.md | 23 +++- cmd/gdocs-cli/main.go | 16 ++- internal/auth/oauth.go | 4 +- internal/gdocs/comments.go | 86 ++++++++++++++ internal/markdown/comments.go | 72 ++++++++++++ internal/markdown/comments_test.go | 180 +++++++++++++++++++++++++++++ internal/markdown/converter.go | 20 +++- 8 files changed, 395 insertions(+), 10 deletions(-) create mode 100644 internal/gdocs/comments.go create mode 100644 internal/markdown/comments.go create mode 100644 internal/markdown/comments_test.go diff --git a/.gitignore b/.gitignore index b4f5f18..af4d36c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ credentials.json -.claude/settings.local.json \ No newline at end of file +.claude/settings.local.json +/gdocs +/gdocs-cli diff --git a/README.md b/README.md index af60506..5b5ed0d 100644 --- a/README.md +++ b/README.md @@ -144,6 +144,25 @@ The tool will automatically use the cached token - no browser interaction needed ./gdocs-cli --url="..." | grep "keyword" ``` +### Include Comments + +Use the `--comments` flag to include document comments in the markdown output: + +```bash +./gdocs-cli --url="https://docs.google.com/document/d/YOUR_DOC_ID/edit" --comments +``` + +This appends a `## Comments` section at the end of the markdown with quoted text, author, date, and replies. + +> **⚠️ Important:** The `--comments` flag requires the `https://www.googleapis.com/auth/drive.readonly` scope. If you previously authenticated without this scope, you need to delete your cached token and re-authenticate: +> +> ```bash +> rm ~/.config/gdocs-cli/token.json +> ./gdocs-cli --init +> ``` +> +> Also make sure you don't have non-HTTPS redirect URIs in any of your Google OAuth clients, as Google requires HTTPS for the Drive API scope. + ### Clean Output (Suppress Logs) Use the `--clean` flag to suppress all log output and only show the markdown: @@ -219,7 +238,7 @@ modified: (if available) - **Images:** Inline images are not currently supported - **Drawings:** Not supported - will be skipped - **Equations:** Not supported - will be skipped -- **Comments:** Not included in output (not in API response by default) +- **Comments:** Supported via `--comments` flag (requires Drive API scope, see below) - **Metadata:** Author and dates require Google Drive API (not implemented in this version) ## Troubleshooting @@ -334,7 +353,7 @@ go test ./internal/auth -v - **Credentials file:** Never commit your `credentials.json` to version control - **Token cache:** Tokens are stored in `~/.config/gdocs-cli/token.json` with 0600 permissions (read/write for owner only) -- **OAuth scope:** The tool only requests `documents.readonly` scope - no write access +- **OAuth scope:** The tool requests `documents.readonly` and `drive.readonly` scopes - no write access - **Config directory:** Created with 0700 permissions (accessible only by owner) ## License diff --git a/cmd/gdocs-cli/main.go b/cmd/gdocs-cli/main.go index c262116..8b99ca7 100644 --- a/cmd/gdocs-cli/main.go +++ b/cmd/gdocs-cli/main.go @@ -23,6 +23,7 @@ func main() { configFlag := flag.String("config", "", "Path to OAuth credentials JSON file (defaults to ~/.config/gdocs-cli/config.json)") initFlag := flag.Bool("init", false, "Initialize OAuth and save token to default location") cleanFlag := flag.Bool("clean", false, "Clean output (suppress all logs, only output markdown)") + commentsFlag := flag.Bool("comments", false, "Include document comments in the markdown output") instructionFlag := flag.Bool("instruction", false, "Print integration instructions for AI coding agents") flag.Parse() @@ -66,13 +67,13 @@ func main() { } // Run the main logic - if err := run(*urlFlag, configPath); err != nil { + if err := run(*urlFlag, configPath, *commentsFlag); err != nil { fmt.Fprintf(os.Stderr, "Error: %v\n", err) os.Exit(1) } } -func run(docURL, credPath string) error { +func run(docURL, credPath string, includeComments bool) error { ctx := context.Background() // Extract document ID from URL @@ -130,6 +131,17 @@ func run(docURL, credPath string) error { converter = markdown.NewConverter(doc) } + // Fetch and attach comments if requested + if includeComments { + log.Println("Fetching comments...") + comments, err := gdocs.FetchComments(ctx, httpClient, docID) + if err != nil { + return fmt.Errorf("failed to fetch comments: %w", err) + } + log.Printf("Found %d comment(s)", len(comments)) + converter.SetComments(comments) + } + markdownOutput, err := converter.Convert() if err != nil { return fmt.Errorf("conversion failed: %w", err) diff --git a/internal/auth/oauth.go b/internal/auth/oauth.go index 3ec213c..08b0ed4 100644 --- a/internal/auth/oauth.go +++ b/internal/auth/oauth.go @@ -20,6 +20,8 @@ const ( // Google Docs API scope for read-only access docsScope = "https://www.googleapis.com/auth/documents.readonly" + // Google Drive API scope for read-only access (used for fetching comments) + driveReadonlyScope = "https://www.googleapis.com/auth/drive.readonly" ) // Authenticator handles OAuth2 authentication for Google Docs API. @@ -37,7 +39,7 @@ func NewAuthenticator(credPath string) (*Authenticator, error) { } // Parse credentials and create OAuth2 config - config, err := google.ConfigFromJSON(credBytes, docsScope) + config, err := google.ConfigFromJSON(credBytes, docsScope, driveReadonlyScope) if err != nil { return nil, fmt.Errorf("failed to parse credentials: %w", err) } diff --git a/internal/gdocs/comments.go b/internal/gdocs/comments.go new file mode 100644 index 0000000..f97e84e --- /dev/null +++ b/internal/gdocs/comments.go @@ -0,0 +1,86 @@ +package gdocs + +import ( + "context" + "fmt" + "net/http" + + "google.golang.org/api/drive/v3" + "google.golang.org/api/option" +) + +// Comment represents a simplified Google Docs comment. +type Comment struct { + Author string + Content string + QuotedText string + CreatedTime string + Resolved bool + Replies []Reply +} + +// Reply represents a reply to a comment. +type Reply struct { + Author string + Content string + CreatedTime string +} + +// FetchComments retrieves all comments for a document using the Drive API. +func FetchComments(ctx context.Context, httpClient *http.Client, docID string) ([]Comment, error) { + srv, err := drive.NewService(ctx, option.WithHTTPClient(httpClient)) + if err != nil { + return nil, fmt.Errorf("unable to create Drive service: %w", err) + } + + var comments []Comment + pageToken := "" + for { + call := srv.Comments.List(docID).Fields("comments(author(displayName),content,quotedFileContent,createdTime,resolved,replies(author(displayName),content,createdTime)),nextPageToken").PageSize(100) + if pageToken != "" { + call = call.PageToken(pageToken) + } + resp, err := call.Do() + if err != nil { + return nil, fmt.Errorf("unable to retrieve comments: %w", err) + } + + for _, c := range resp.Comments { + if c.Deleted { + continue + } + comment := Comment{ + Content: c.Content, + CreatedTime: c.CreatedTime, + Resolved: c.Resolved, + } + if c.Author != nil { + comment.Author = c.Author.DisplayName + } + if c.QuotedFileContent != nil { + comment.QuotedText = c.QuotedFileContent.Value + } + for _, r := range c.Replies { + if r.Deleted { + continue + } + reply := Reply{ + Content: r.Content, + CreatedTime: r.CreatedTime, + } + if r.Author != nil { + reply.Author = r.Author.DisplayName + } + comment.Replies = append(comment.Replies, reply) + } + comments = append(comments, comment) + } + + pageToken = resp.NextPageToken + if pageToken == "" { + break + } + } + + return comments, nil +} diff --git a/internal/markdown/comments.go b/internal/markdown/comments.go new file mode 100644 index 0000000..acc4a67 --- /dev/null +++ b/internal/markdown/comments.go @@ -0,0 +1,72 @@ +package markdown + +import ( + "fmt" + "strings" + "time" + + "github.com/famasya/gdocs-cli/internal/gdocs" +) + +// ConvertComments renders a list of comments as a markdown section. +func ConvertComments(comments []gdocs.Comment) string { + if len(comments) == 0 { + return "" + } + + var builder strings.Builder + builder.WriteString("## Comments\n\n") + + for _, c := range comments { + if c.QuotedText != "" { + builder.WriteString("> ") + builder.WriteString(strings.ReplaceAll(c.QuotedText, "\n", "\n> ")) + builder.WriteString("\n\n") + } + + author := c.Author + if author == "" { + author = "Unknown" + } + builder.WriteString(fmt.Sprintf("**%s**", author)) + if ts := formatTime(c.CreatedTime); ts != "" { + builder.WriteString(fmt.Sprintf(" (%s)", ts)) + } + if c.Resolved { + builder.WriteString(" ✓ resolved") + } + builder.WriteString(": ") + builder.WriteString(c.Content) + builder.WriteString("\n") + + for _, r := range c.Replies { + rAuthor := r.Author + if rAuthor == "" { + rAuthor = "Unknown" + } + builder.WriteString(fmt.Sprintf(" ↳ **%s**", rAuthor)) + if ts := formatTime(r.CreatedTime); ts != "" { + builder.WriteString(fmt.Sprintf(" (%s)", ts)) + } + builder.WriteString(": ") + builder.WriteString(r.Content) + builder.WriteString("\n") + } + + builder.WriteString("\n") + } + + return builder.String() +} + +// formatTime converts an RFC 3339 timestamp to a short date string. +func formatTime(rfc3339 string) string { + if rfc3339 == "" { + return "" + } + t, err := time.Parse(time.RFC3339, rfc3339) + if err != nil { + return "" + } + return t.Format("2006-01-02") +} diff --git a/internal/markdown/comments_test.go b/internal/markdown/comments_test.go new file mode 100644 index 0000000..8e8ee52 --- /dev/null +++ b/internal/markdown/comments_test.go @@ -0,0 +1,180 @@ +package markdown + +import ( + "testing" + + "github.com/famasya/gdocs-cli/internal/gdocs" +) + +func TestConvertComments(t *testing.T) { + tests := []struct { + name string + comments []gdocs.Comment + want string + }{ + { + name: "nil comments", + comments: nil, + want: "", + }, + { + name: "empty comments", + comments: []gdocs.Comment{}, + want: "", + }, + { + name: "single comment without quoted text", + comments: []gdocs.Comment{ + { + Author: "Alice", + Content: "This needs clarification.", + CreatedTime: "2025-01-15T10:30:00Z", + }, + }, + want: "## Comments\n\n**Alice** (2025-01-15): This needs clarification.\n\n", + }, + { + name: "single comment with quoted text", + comments: []gdocs.Comment{ + { + Author: "Bob", + Content: "Typo here.", + QuotedText: "the orignal text", + CreatedTime: "2025-03-20T14:00:00Z", + }, + }, + want: "## Comments\n\n> the orignal text\n\n**Bob** (2025-03-20): Typo here.\n\n", + }, + { + name: "resolved comment", + comments: []gdocs.Comment{ + { + Author: "Carol", + Content: "Fixed now.", + CreatedTime: "2025-02-01T08:00:00Z", + Resolved: true, + }, + }, + want: "## Comments\n\n**Carol** (2025-02-01) ✓ resolved: Fixed now.\n\n", + }, + { + name: "comment with replies", + comments: []gdocs.Comment{ + { + Author: "Dave", + Content: "Should we change this?", + CreatedTime: "2025-04-10T12:00:00Z", + Replies: []gdocs.Reply{ + { + Author: "Eve", + Content: "Yes, I agree.", + CreatedTime: "2025-04-10T13:00:00Z", + }, + { + Author: "Dave", + Content: "Done.", + CreatedTime: "2025-04-10T14:00:00Z", + }, + }, + }, + }, + want: "## Comments\n\n**Dave** (2025-04-10): Should we change this?\n ↳ **Eve** (2025-04-10): Yes, I agree.\n ↳ **Dave** (2025-04-10): Done.\n\n", + }, + { + name: "comment with multiline quoted text", + comments: []gdocs.Comment{ + { + Author: "Frank", + Content: "This paragraph is too long.", + QuotedText: "line one\nline two", + CreatedTime: "2025-05-01T09:00:00Z", + }, + }, + want: "## Comments\n\n> line one\n> line two\n\n**Frank** (2025-05-01): This paragraph is too long.\n\n", + }, + { + name: "comment with unknown author", + comments: []gdocs.Comment{ + { + Content: "Anonymous feedback.", + CreatedTime: "2025-06-01T10:00:00Z", + }, + }, + want: "## Comments\n\n**Unknown** (2025-06-01): Anonymous feedback.\n\n", + }, + { + name: "comment with no timestamp", + comments: []gdocs.Comment{ + { + Author: "Grace", + Content: "No date here.", + }, + }, + want: "## Comments\n\n**Grace**: No date here.\n\n", + }, + { + name: "multiple comments", + comments: []gdocs.Comment{ + { + Author: "Alice", + Content: "First comment.", + CreatedTime: "2025-01-01T00:00:00Z", + }, + { + Author: "Bob", + Content: "Second comment.", + QuotedText: "some text", + CreatedTime: "2025-01-02T00:00:00Z", + }, + }, + want: "## Comments\n\n**Alice** (2025-01-01): First comment.\n\n> some text\n\n**Bob** (2025-01-02): Second comment.\n\n", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := ConvertComments(tt.comments) + if got != tt.want { + t.Errorf("ConvertComments() = %q, want %q", got, tt.want) + } + }) + } +} + +func TestFormatTime(t *testing.T) { + tests := []struct { + name string + input string + want string + }{ + { + name: "valid RFC3339", + input: "2025-01-15T10:30:00Z", + want: "2025-01-15", + }, + { + name: "valid RFC3339 with offset", + input: "2025-06-20T14:30:00+07:00", + want: "2025-06-20", + }, + { + name: "empty string", + input: "", + want: "", + }, + { + name: "invalid format", + input: "not-a-date", + want: "", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := formatTime(tt.input) + if got != tt.want { + t.Errorf("formatTime(%q) = %q, want %q", tt.input, got, tt.want) + } + }) + } +} diff --git a/internal/markdown/converter.go b/internal/markdown/converter.go index 1615887..913f09a 100644 --- a/internal/markdown/converter.go +++ b/internal/markdown/converter.go @@ -4,15 +4,17 @@ import ( "fmt" "strings" + "github.com/famasya/gdocs-cli/internal/gdocs" "google.golang.org/api/docs/v1" ) // Converter handles the conversion of Google Docs to markdown. type Converter struct { - doc *docs.Document - body *docs.Body - title string - tabName string + doc *docs.Document + body *docs.Body + title string + tabName string + comments []gdocs.Comment } // NewConverter creates a new Converter for the given document. @@ -50,6 +52,11 @@ func NewConverterFromTab(doc *docs.Document, tab *docs.Tab) *Converter { return c } +// SetComments sets the comments to be appended to the markdown output. +func (c *Converter) SetComments(comments []gdocs.Comment) { + c.comments = comments +} + // Convert processes the entire document and returns markdown. func (c *Converter) Convert() (string, error) { var builder strings.Builder @@ -68,6 +75,11 @@ func (c *Converter) Convert() (string, error) { builder.WriteString(body) } + // Append comments if present + if len(c.comments) > 0 { + builder.WriteString(ConvertComments(c.comments)) + } + return builder.String(), nil } From 5ca70d12512729871c0c8720c1032532ca8842d8 Mon Sep 17 00:00:00 2001 From: Abid Famasya Date: Fri, 13 Feb 2026 09:51:54 +0700 Subject: [PATCH 2/4] chore: add gh-cli skills --- .agents/skills/gh-cli/SKILL.md | 2187 ++++++++++++++++++++++++++++++++ .claude/skills/gh-cli | 1 + 2 files changed, 2188 insertions(+) create mode 100644 .agents/skills/gh-cli/SKILL.md create mode 120000 .claude/skills/gh-cli diff --git a/.agents/skills/gh-cli/SKILL.md b/.agents/skills/gh-cli/SKILL.md new file mode 100644 index 0000000..6756f0b --- /dev/null +++ b/.agents/skills/gh-cli/SKILL.md @@ -0,0 +1,2187 @@ +--- +name: gh-cli +description: GitHub CLI (gh) comprehensive reference for repositories, issues, pull requests, Actions, projects, releases, gists, codespaces, organizations, extensions, and all GitHub operations from the command line. +--- + +# GitHub CLI (gh) + +Comprehensive reference for GitHub CLI (gh) - work seamlessly with GitHub from the command line. + +**Version:** 2.85.0 (current as of January 2026) + +## Prerequisites + +### Installation + +```bash +# macOS +brew install gh + +# Linux +curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg +echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null +sudo apt update +sudo apt install gh + +# Windows +winget install --id GitHub.cli + +# Verify installation +gh --version +``` + +### Authentication + +```bash +# Interactive login (default: github.com) +gh auth login + +# Login with specific hostname +gh auth login --hostname enterprise.internal + +# Login with token +gh auth login --with-token < mytoken.txt + +# Check authentication status +gh auth status + +# Switch accounts +gh auth switch --hostname github.com --user username + +# Logout +gh auth logout --hostname github.com --user username +``` + +### Setup Git Integration + +```bash +# Configure git to use gh as credential helper +gh auth setup-git + +# View active token +gh auth token + +# Refresh authentication scopes +gh auth refresh --scopes write:org,read:public_key +``` + +## CLI Structure + +``` +gh # Root command +├── auth # Authentication +│ ├── login +│ ├── logout +│ ├── refresh +│ ├── setup-git +│ ├── status +│ ├── switch +│ └── token +├── browse # Open in browser +├── codespace # GitHub Codespaces +│ ├── code +│ ├── cp +│ ├── create +│ ├── delete +│ ├── edit +│ ├── jupyter +│ ├── list +│ ├── logs +│ ├── ports +│ ├── rebuild +│ ├── ssh +│ ├── stop +│ └── view +├── gist # Gists +│ ├── clone +│ ├── create +│ ├── delete +│ ├── edit +│ ├── list +│ ├── rename +│ └── view +├── issue # Issues +│ ├── create +│ ├── list +│ ├── status +│ ├── close +│ ├── comment +│ ├── delete +│ ├── develop +│ ├── edit +│ ├── lock +│ ├── pin +│ ├── reopen +│ ├── transfer +│ ├── unlock +│ └── view +├── org # Organizations +│ └── list +├── pr # Pull Requests +│ ├── create +│ ├── list +│ ├── status +│ ├── checkout +│ ├── checks +│ ├── close +│ ├── comment +│ ├── diff +│ ├── edit +│ ├── lock +│ ├── merge +│ ├── ready +│ ├── reopen +│ ├── revert +│ ├── review +│ ├── unlock +│ ├── update-branch +│ └── view +├── project # Projects +│ ├── close +│ ├── copy +│ ├── create +│ ├── delete +│ ├── edit +│ ├── field-create +│ ├── field-delete +│ ├── field-list +│ ├── item-add +│ ├── item-archive +│ ├── item-create +│ ├── item-delete +│ ├── item-edit +│ ├── item-list +│ ├── link +│ ├── list +│ ├── mark-template +│ ├── unlink +│ └── view +├── release # Releases +│ ├── create +│ ├── list +│ ├── delete +│ ├── delete-asset +│ ├── download +│ ├── edit +│ ├── upload +│ ├── verify +│ ├── verify-asset +│ └── view +├── repo # Repositories +│ ├── create +│ ├── list +│ ├── archive +│ ├── autolink +│ ├── clone +│ ├── delete +│ ├── deploy-key +│ ├── edit +│ ├── fork +│ ├── gitignore +│ ├── license +│ ├── rename +│ ├── set-default +│ ├── sync +│ ├── unarchive +│ └── view +├── cache # Actions caches +│ ├── delete +│ └── list +├── run # Workflow runs +│ ├── cancel +│ ├── delete +│ ├── download +│ ├── list +│ ├── rerun +│ ├── view +│ └── watch +├── workflow # Workflows +│ ├── disable +│ ├── enable +│ ├── list +│ ├── run +│ └── view +├── agent-task # Agent tasks +├── alias # Command aliases +│ ├── delete +│ ├── import +│ ├── list +│ └── set +├── api # API requests +├── attestation # Artifact attestations +│ ├── download +│ ├── trusted-root +│ └── verify +├── completion # Shell completion +├── config # Configuration +│ ├── clear-cache +│ ├── get +│ ├── list +│ └── set +├── extension # Extensions +│ ├── browse +│ ├── create +│ ├── exec +│ ├── install +│ ├── list +│ ├── remove +│ ├── search +│ └── upgrade +├── gpg-key # GPG keys +│ ├── add +│ ├── delete +│ └── list +├── label # Labels +│ ├── clone +│ ├── create +│ ├── delete +│ ├── edit +│ └── list +├── preview # Preview features +├── ruleset # Rulesets +│ ├── check +│ ├── list +│ └── view +├── search # Search +│ ├── code +│ ├── commits +│ ├── issues +│ ├── prs +│ └── repos +├── secret # Secrets +│ ├── delete +│ ├── list +│ └── set +├── ssh-key # SSH keys +│ ├── add +│ ├── delete +│ └── list +├── status # Status overview +└── variable # Variables + ├── delete + ├── get + ├── list + └── set +``` + +## Configuration + +### Global Configuration + +```bash +# List all configuration +gh config list + +# Get specific configuration value +gh config list git_protocol +gh config get editor + +# Set configuration value +gh config set editor vim +gh config set git_protocol ssh +gh config set prompt disabled +gh config set pager "less -R" + +# Clear configuration cache +gh config clear-cache +``` + +### Environment Variables + +```bash +# GitHub token (for automation) +export GH_TOKEN=ghp_xxxxxxxxxxxx + +# GitHub hostname +export GH_HOST=github.com + +# Disable prompts +export GH_PROMPT_DISABLED=true + +# Custom editor +export GH_EDITOR=vim + +# Custom pager +export GH_PAGER=less + +# HTTP timeout +export GH_TIMEOUT=30 + +# Custom repository (override default) +export GH_REPO=owner/repo + +# Custom git protocol +export GH_ENTERPRISE_HOSTNAME=hostname +``` + +## Authentication (gh auth) + +### Login + +```bash +# Interactive login +gh auth login + +# Web-based authentication +gh auth login --web + +# With clipboard for OAuth code +gh auth login --web --clipboard + +# With specific git protocol +gh auth login --git-protocol ssh + +# With custom hostname (GitHub Enterprise) +gh auth login --hostname enterprise.internal + +# Login with token from stdin +gh auth login --with-token < token.txt + +# Insecure storage (plain text) +gh auth login --insecure-storage +``` + +### Status + +```bash +# Show all authentication status +gh auth status + +# Show active account only +gh auth status --active + +# Show specific hostname +gh auth status --hostname github.com + +# Show token in output +gh auth status --show-token + +# JSON output +gh auth status --json hosts + +# Filter with jq +gh auth status --json hosts --jq '.hosts | add' +``` + +### Switch Accounts + +```bash +# Interactive switch +gh auth switch + +# Switch to specific user/host +gh auth switch --hostname github.com --user monalisa +``` + +### Token + +```bash +# Print authentication token +gh auth token + +# Token for specific host/user +gh auth token --hostname github.com --user monalisa +``` + +### Refresh + +```bash +# Refresh credentials +gh auth refresh + +# Add scopes +gh auth refresh --scopes write:org,read:public_key + +# Remove scopes +gh auth refresh --remove-scopes delete_repo + +# Reset to default scopes +gh auth refresh --reset-scopes + +# With clipboard +gh auth refresh --clipboard +``` + +### Setup Git + +```bash +# Setup git credential helper +gh auth setup-git + +# Setup for specific host +gh auth setup-git --hostname enterprise.internal + +# Force setup even if host not known +gh auth setup-git --hostname enterprise.internal --force +``` + +## Browse (gh browse) + +```bash +# Open repository in browser +gh browse + +# Open specific path +gh browse script/ +gh browse main.go:312 + +# Open issue or PR +gh browse 123 + +# Open commit +gh browse 77507cd94ccafcf568f8560cfecde965fcfa63 + +# Open with specific branch +gh browse main.go --branch bug-fix + +# Open different repository +gh browse --repo owner/repo + +# Open specific pages +gh browse --actions # Actions tab +gh browse --projects # Projects tab +gh browse --releases # Releases tab +gh browse --settings # Settings page +gh browse --wiki # Wiki page + +# Print URL instead of opening +gh browse --no-browser +``` + +## Repositories (gh repo) + +### Create Repository + +```bash +# Create new repository +gh repo create my-repo + +# Create with description +gh repo create my-repo --description "My awesome project" + +# Create public repository +gh repo create my-repo --public + +# Create private repository +gh repo create my-repo --private + +# Create with homepage +gh repo create my-repo --homepage https://example.com + +# Create with license +gh repo create my-repo --license mit + +# Create with gitignore +gh repo create my-repo --gitignore python + +# Initialize as template repository +gh repo create my-repo --template + +# Create repository in organization +gh repo create org/my-repo + +# Create without cloning locally +gh repo create my-repo --source=. + +# Disable issues +gh repo create my-repo --disable-issues + +# Disable wiki +gh repo create my-repo --disable-wiki +``` + +### Clone Repository + +```bash +# Clone repository +gh repo clone owner/repo + +# Clone to specific directory +gh repo clone owner/repo my-directory + +# Clone with different branch +gh repo clone owner/repo --branch develop +``` + +### List Repositories + +```bash +# List all repositories +gh repo list + +# List repositories for owner +gh repo list owner + +# Limit results +gh repo list --limit 50 + +# Public repositories only +gh repo list --public + +# Source repositories only (not forks) +gh repo list --source + +# JSON output +gh repo list --json name,visibility,owner + +# Table output +gh repo list --limit 100 | tail -n +2 + +# Filter with jq +gh repo list --json name --jq '.[].name' +``` + +### View Repository + +```bash +# View repository details +gh repo view + +# View specific repository +gh repo view owner/repo + +# JSON output +gh repo view --json name,description,defaultBranchRef + +# View in browser +gh repo view --web +``` + +### Edit Repository + +```bash +# Edit description +gh repo edit --description "New description" + +# Set homepage +gh repo edit --homepage https://example.com + +# Change visibility +gh repo edit --visibility private +gh repo edit --visibility public + +# Enable/disable features +gh repo edit --enable-issues +gh repo edit --disable-issues +gh repo edit --enable-wiki +gh repo edit --disable-wiki +gh repo edit --enable-projects +gh repo edit --disable-projects + +# Set default branch +gh repo edit --default-branch main + +# Rename repository +gh repo rename new-name + +# Archive repository +gh repo archive +gh repo unarchive +``` + +### Delete Repository + +```bash +# Delete repository +gh repo delete owner/repo + +# Confirm without prompt +gh repo delete owner/repo --yes +``` + +### Fork Repository + +```bash +# Fork repository +gh repo fork owner/repo + +# Fork to organization +gh repo fork owner/repo --org org-name + +# Clone after forking +gh repo fork owner/repo --clone + +# Remote name for fork +gh repo fork owner/repo --remote-name upstream +``` + +### Sync Fork + +```bash +# Sync fork with upstream +gh repo sync + +# Sync specific branch +gh repo sync --branch feature + +# Force sync +gh repo sync --force +``` + +### Set Default Repository + +```bash +# Set default repository for current directory +gh repo set-default + +# Set default explicitly +gh repo set-default owner/repo + +# Unset default +gh repo set-default --unset +``` + +### Repository Autolinks + +```bash +# List autolinks +gh repo autolink list + +# Add autolink +gh repo autolink add \ + --key-prefix JIRA- \ + --url-template https://jira.example.com/browse/ + +# Delete autolink +gh repo autolink delete 12345 +``` + +### Repository Deploy Keys + +```bash +# List deploy keys +gh repo deploy-key list + +# Add deploy key +gh repo deploy-key add ~/.ssh/id_rsa.pub \ + --title "Production server" \ + --read-only + +# Delete deploy key +gh repo deploy-key delete 12345 +``` + +### Gitignore and License + +```bash +# View gitignore template +gh repo gitignore + +# View license template +gh repo license mit + +# License with full name +gh repo license mit --fullname "John Doe" +``` + +## Issues (gh issue) + +### Create Issue + +```bash +# Create issue interactively +gh issue create + +# Create with title +gh issue create --title "Bug: Login not working" + +# Create with title and body +gh issue create \ + --title "Bug: Login not working" \ + --body "Steps to reproduce..." + +# Create with body from file +gh issue create --body-file issue.md + +# Create with labels +gh issue create --title "Fix bug" --labels bug,high-priority + +# Create with assignees +gh issue create --title "Fix bug" --assignee user1,user2 + +# Create in specific repository +gh issue create --repo owner/repo --title "Issue title" + +# Create issue from web +gh issue create --web +``` + +### List Issues + +```bash +# List all open issues +gh issue list + +# List all issues (including closed) +gh issue list --state all + +# List closed issues +gh issue list --state closed + +# Limit results +gh issue list --limit 50 + +# Filter by assignee +gh issue list --assignee username +gh issue list --assignee @me + +# Filter by labels +gh issue list --labels bug,enhancement + +# Filter by milestone +gh issue list --milestone "v1.0" + +# Search/filter +gh issue list --search "is:open is:issue label:bug" + +# JSON output +gh issue list --json number,title,state,author + +# Table view +gh issue list --json number,title,labels --jq '.[] | [.number, .title, .labels[].name] | @tsv' + +# Show comments count +gh issue list --json number,title,comments --jq '.[] | [.number, .title, .comments]' + +# Sort by +gh issue list --sort created --order desc +``` + +### View Issue + +```bash +# View issue +gh issue view 123 + +# View with comments +gh issue view 123 --comments + +# View in browser +gh issue view 123 --web + +# JSON output +gh issue view 123 --json title,body,state,labels,comments + +# View specific fields +gh issue view 123 --json title --jq '.title' +``` + +### Edit Issue + +```bash +# Edit interactively +gh issue edit 123 + +# Edit title +gh issue edit 123 --title "New title" + +# Edit body +gh issue edit 123 --body "New description" + +# Add labels +gh issue edit 123 --add-label bug,high-priority + +# Remove labels +gh issue edit 123 --remove-label stale + +# Add assignees +gh issue edit 123 --add-assignee user1,user2 + +# Remove assignees +gh issue edit 123 --remove-assignee user1 + +# Set milestone +gh issue edit 123 --milestone "v1.0" +``` + +### Close/Reopen Issue + +```bash +# Close issue +gh issue close 123 + +# Close with comment +gh issue close 123 --comment "Fixed in PR #456" + +# Reopen issue +gh issue reopen 123 +``` + +### Comment on Issue + +```bash +# Add comment +gh issue comment 123 --body "This looks good!" + +# Edit comment +gh issue comment 123 --edit 456789 --body "Updated comment" + +# Delete comment +gh issue comment 123 --delete 456789 +``` + +### Issue Status + +```bash +# Show issue status summary +gh issue status + +# Status for specific repository +gh issue status --repo owner/repo +``` + +### Pin/Unpin Issues + +```bash +# Pin issue (pinned to repo dashboard) +gh issue pin 123 + +# Unpin issue +gh issue unpin 123 +``` + +### Lock/Unlock Issue + +```bash +# Lock conversation +gh issue lock 123 + +# Lock with reason +gh issue lock 123 --reason off-topic + +# Unlock +gh issue unlock 123 +``` + +### Transfer Issue + +```bash +# Transfer to another repository +gh issue transfer 123 --repo owner/new-repo +``` + +### Delete Issue + +```bash +# Delete issue +gh issue delete 123 + +# Confirm without prompt +gh issue delete 123 --yes +``` + +### Develop Issue (Draft PR) + +```bash +# Create draft PR from issue +gh issue develop 123 + +# Create in specific branch +gh issue develop 123 --branch fix/issue-123 + +# Create with base branch +gh issue develop 123 --base main +``` + +## Pull Requests (gh pr) + +### Create Pull Request + +```bash +# Create PR interactively +gh pr create + +# Create with title +gh pr create --title "Feature: Add new functionality" + +# Create with title and body +gh pr create \ + --title "Feature: Add new functionality" \ + --body "This PR adds..." + +# Fill body from template +gh pr create --body-file .github/PULL_REQUEST_TEMPLATE.md + +# Set base branch +gh pr create --base main + +# Set head branch (default: current branch) +gh pr create --head feature-branch + +# Create draft PR +gh pr create --draft + +# Add assignees +gh pr create --assignee user1,user2 + +# Add reviewers +gh pr create --reviewer user1,user2 + +# Add labels +gh pr create --labels enhancement,feature + +# Link to issue +gh pr create --issue 123 + +# Create in specific repository +gh pr create --repo owner/repo + +# Open in browser after creation +gh pr create --web +``` + +### List Pull Requests + +```bash +# List open PRs +gh pr list + +# List all PRs +gh pr list --state all + +# List merged PRs +gh pr list --state merged + +# List closed (not merged) PRs +gh pr list --state closed + +# Filter by head branch +gh pr list --head feature-branch + +# Filter by base branch +gh pr list --base main + +# Filter by author +gh pr list --author username +gh pr list --author @me + +# Filter by assignee +gh pr list --assignee username + +# Filter by labels +gh pr list --labels bug,enhancement + +# Limit results +gh pr list --limit 50 + +# Search +gh pr list --search "is:open is:pr label:review-required" + +# JSON output +gh pr list --json number,title,state,author,headRefName + +# Show check status +gh pr list --json number,title,statusCheckRollup --jq '.[] | [.number, .title, .statusCheckRollup[]?.status]' + +# Sort by +gh pr list --sort created --order desc +``` + +### View Pull Request + +```bash +# View PR +gh pr view 123 + +# View with comments +gh pr view 123 --comments + +# View in browser +gh pr view 123 --web + +# JSON output +gh pr view 123 --json title,body,state,author,commits,files + +# View diff +gh pr view 123 --json files --jq '.files[].path' + +# View with jq query +gh pr view 123 --json title,state --jq '"\(.title): \(.state)"' +``` + +### Checkout Pull Request + +```bash +# Checkout PR branch +gh pr checkout 123 + +# Checkout with specific branch name +gh pr checkout 123 --branch name-123 + +# Force checkout +gh pr checkout 123 --force +``` + +### Diff Pull Request + +```bash +# View PR diff +gh pr diff 123 + +# View diff with color +gh pr diff 123 --color always + +# Output to file +gh pr diff 123 > pr-123.patch + +# View diff of specific files +gh pr diff 123 --name-only +``` + +### Merge Pull Request + +```bash +# Merge PR +gh pr merge 123 + +# Merge with specific method +gh pr merge 123 --merge +gh pr merge 123 --squash +gh pr merge 123 --rebase + +# Delete branch after merge +gh pr merge 123 --delete-branch + +# Merge with comment +gh pr merge 123 --subject "Merge PR #123" --body "Merging feature" + +# Merge draft PR +gh pr merge 123 --admin + +# Force merge (skip checks) +gh pr merge 123 --admin +``` + +### Close Pull Request + +```bash +# Close PR (as draft, not merge) +gh pr close 123 + +# Close with comment +gh pr close 123 --comment "Closing due to..." +``` + +### Reopen Pull Request + +```bash +# Reopen closed PR +gh pr reopen 123 +``` + +### Edit Pull Request + +```bash +# Edit interactively +gh pr edit 123 + +# Edit title +gh pr edit 123 --title "New title" + +# Edit body +gh pr edit 123 --body "New description" + +# Add labels +gh pr edit 123 --add-label bug,enhancement + +# Remove labels +gh pr edit 123 --remove-label stale + +# Add assignees +gh pr edit 123 --add-assignee user1,user2 + +# Remove assignees +gh pr edit 123 --remove-assignee user1 + +# Add reviewers +gh pr edit 123 --add-reviewer user1,user2 + +# Remove reviewers +gh pr edit 123 --remove-reviewer user1 + +# Mark as ready for review +gh pr edit 123 --ready +``` + +### Ready for Review + +```bash +# Mark draft PR as ready +gh pr ready 123 +``` + +### Pull Request Checks + +```bash +# View PR checks +gh pr checks 123 + +# Watch checks in real-time +gh pr checks 123 --watch + +# Watch interval (seconds) +gh pr checks 123 --watch --interval 5 +``` + +### Comment on Pull Request + +```bash +# Add comment +gh pr comment 123 --body "Looks good!" + +# Comment on specific line +gh pr comment 123 --body "Fix this" \ + --repo owner/repo \ + --head-owner owner --head-branch feature + +# Edit comment +gh pr comment 123 --edit 456789 --body "Updated" + +# Delete comment +gh pr comment 123 --delete 456789 +``` + +### Review Pull Request + +```bash +# Review PR (opens editor) +gh pr review 123 + +# Approve PR +gh pr review 123 --approve --body "LGTM!" + +# Request changes +gh pr review 123 --request-changes \ + --body "Please fix these issues" + +# Comment on PR +gh pr review 123 --comment --body "Some thoughts..." + +# Dismiss review +gh pr review 123 --dismiss +``` + +### Update Branch + +```bash +# Update PR branch with latest base branch +gh pr update-branch 123 + +# Force update +gh pr update-branch 123 --force + +# Use merge strategy +gh pr update-branch 123 --merge +``` + +### Lock/Unlock Pull Request + +```bash +# Lock PR conversation +gh pr lock 123 + +# Lock with reason +gh pr lock 123 --reason off-topic + +# Unlock +gh pr unlock 123 +``` + +### Revert Pull Request + +```bash +# Revert merged PR +gh pr revert 123 + +# Revert with specific branch name +gh pr revert 123 --branch revert-pr-123 +``` + +### Pull Request Status + +```bash +# Show PR status summary +gh pr status + +# Status for specific repository +gh pr status --repo owner/repo +``` + +## GitHub Actions + +### Workflow Runs (gh run) + +```bash +# List workflow runs +gh run list + +# List for specific workflow +gh run list --workflow "ci.yml" + +# List for specific branch +gh run list --branch main + +# Limit results +gh run list --limit 20 + +# JSON output +gh run list --json databaseId,status,conclusion,headBranch + +# View run details +gh run view 123456789 + +# View run with verbose logs +gh run view 123456789 --log + +# View specific job +gh run view 123456789 --job 987654321 + +# View in browser +gh run view 123456789 --web + +# Watch run in real-time +gh run watch 123456789 + +# Watch with interval +gh run watch 123456789 --interval 5 + +# Rerun failed run +gh run rerun 123456789 + +# Rerun specific job +gh run rerun 123456789 --job 987654321 + +# Cancel run +gh run cancel 123456789 + +# Delete run +gh run delete 123456789 + +# Download run artifacts +gh run download 123456789 + +# Download specific artifact +gh run download 123456789 --name build + +# Download to directory +gh run download 123456789 --dir ./artifacts +``` + +### Workflows (gh workflow) + +```bash +# List workflows +gh workflow list + +# View workflow details +gh workflow view ci.yml + +# View workflow YAML +gh workflow view ci.yml --yaml + +# View in browser +gh workflow view ci.yml --web + +# Enable workflow +gh workflow enable ci.yml + +# Disable workflow +gh workflow disable ci.yml + +# Run workflow manually +gh workflow run ci.yml + +# Run with inputs +gh workflow run ci.yml \ + --raw-field \ + version="1.0.0" \ + environment="production" + +# Run from specific branch +gh workflow run ci.yml --ref develop +``` + +### Action Caches (gh cache) + +```bash +# List caches +gh cache list + +# List for specific branch +gh cache list --branch main + +# List with limit +gh cache list --limit 50 + +# Delete cache +gh cache delete 123456789 + +# Delete all caches +gh cache delete --all +``` + +### Action Secrets (gh secret) + +```bash +# List secrets +gh secret list + +# Set secret (prompts for value) +gh secret set MY_SECRET + +# Set secret from environment +echo "$MY_SECRET" | gh secret set MY_SECRET + +# Set secret for specific environment +gh secret set MY_SECRET --env production + +# Set secret for organization +gh secret set MY_SECRET --org orgname + +# Delete secret +gh secret delete MY_SECRET + +# Delete from environment +gh secret delete MY_SECRET --env production +``` + +### Action Variables (gh variable) + +```bash +# List variables +gh variable list + +# Set variable +gh variable set MY_VAR "some-value" + +# Set variable for environment +gh variable set MY_VAR "value" --env production + +# Set variable for organization +gh variable set MY_VAR "value" --org orgname + +# Get variable value +gh variable get MY_VAR + +# Delete variable +gh variable delete MY_VAR + +# Delete from environment +gh variable delete MY_VAR --env production +``` + +## Projects (gh project) + +```bash +# List projects +gh project list + +# List for owner +gh project list --owner owner + +# Open projects +gh project list --open + +# View project +gh project view 123 + +# View project items +gh project view 123 --format json + +# Create project +gh project create --title "My Project" + +# Create in organization +gh project create --title "Project" --org orgname + +# Create with readme +gh project create --title "Project" --readme "Description here" + +# Edit project +gh project edit 123 --title "New Title" + +# Delete project +gh project delete 123 + +# Close project +gh project close 123 + +# Copy project +gh project copy 123 --owner target-owner --title "Copy" + +# Mark template +gh project mark-template 123 + +# List fields +gh project field-list 123 + +# Create field +gh project field-create 123 --title "Status" --datatype single_select + +# Delete field +gh project field-delete 123 --id 456 + +# List items +gh project item-list 123 + +# Create item +gh project item-create 123 --title "New item" + +# Add item to project +gh project item-add 123 --owner-owner --repo repo --issue 456 + +# Edit item +gh project item-edit 123 --id 456 --title "Updated title" + +# Delete item +gh project item-delete 123 --id 456 + +# Archive item +gh project item-archive 123 --id 456 + +# Link items +gh project link 123 --id 456 --link-id 789 + +# Unlink items +gh project unlink 123 --id 456 --link-id 789 + +# View project in browser +gh project view 123 --web +``` + +## Releases (gh release) + +```bash +# List releases +gh release list + +# View latest release +gh release view + +# View specific release +gh release view v1.0.0 + +# View in browser +gh release view v1.0.0 --web + +# Create release +gh release create v1.0.0 \ + --notes "Release notes here" + +# Create release with notes from file +gh release create v1.0.0 --notes-file notes.md + +# Create release with target +gh release create v1.0.0 --target main + +# Create release as draft +gh release create v1.0.0 --draft + +# Create pre-release +gh release create v1.0.0 --prerelease + +# Create release with title +gh release create v1.0.0 --title "Version 1.0.0" + +# Upload asset to release +gh release upload v1.0.0 ./file.tar.gz + +# Upload multiple assets +gh release upload v1.0.0 ./file1.tar.gz ./file2.tar.gz + +# Upload with label (casing sensitive) +gh release upload v1.0.0 ./file.tar.gz --casing + +# Delete release +gh release delete v1.0.0 + +# Delete with cleanup tag +gh release delete v1.0.0 --yes + +# Delete specific asset +gh release delete-asset v1.0.0 file.tar.gz + +# Download release assets +gh release download v1.0.0 + +# Download specific asset +gh release download v1.0.0 --pattern "*.tar.gz" + +# Download to directory +gh release download v1.0.0 --dir ./downloads + +# Download archive (zip/tar) +gh release download v1.0.0 --archive zip + +# Edit release +gh release edit v1.0.0 --notes "Updated notes" + +# Verify release signature +gh release verify v1.0.0 + +# Verify specific asset +gh release verify-asset v1.0.0 file.tar.gz +``` + +## Gists (gh gist) + +```bash +# List gists +gh gist list + +# List all gists (including private) +gh gist list --public + +# Limit results +gh gist list --limit 20 + +# View gist +gh gist view abc123 + +# View gist files +gh gist view abc123 --files + +# Create gist +gh gist create script.py + +# Create gist with description +gh gist create script.py --desc "My script" + +# Create public gist +gh gist create script.py --public + +# Create multi-file gist +gh gist create file1.py file2.py + +# Create from stdin +echo "print('hello')" | gh gist create + +# Edit gist +gh gist edit abc123 + +# Delete gist +gh gist delete abc123 + +# Rename gist file +gh gist rename abc123 --filename old.py new.py + +# Clone gist +gh gist clone abc123 + +# Clone to directory +gh gist clone abc123 my-directory +``` + +## Codespaces (gh codespace) + +```bash +# List codespaces +gh codespace list + +# Create codespace +gh codespace create + +# Create with specific repository +gh codespace create --repo owner/repo + +# Create with branch +gh codespace create --branch develop + +# Create with specific machine +gh codespace create --machine premiumLinux + +# View codespace details +gh codespace view + +# SSH into codespace +gh codespace ssh + +# SSH with specific command +gh codespace ssh --command "cd /workspaces && ls" + +# Open codespace in browser +gh codespace code + +# Open in VS Code +gh codespace code --codec + +# Open with specific path +gh codespace code --path /workspaces/repo + +# Stop codespace +gh codespace stop + +# Delete codespace +gh codespace delete + +# View logs +gh codespace logs + +--tail 100 + +# View ports +gh codespace ports + +# Forward port +gh codespace cp 8080:8080 + +# Rebuild codespace +gh codespace rebuild + +# Edit codespace +gh codespace edit --machine standardLinux + +# Jupyter support +gh codespace jupyter + +# Copy files to/from codespace +gh codespace cp file.txt :/workspaces/file.txt +gh codespace cp :/workspaces/file.txt ./file.txt +``` + +## Organizations (gh org) + +```bash +# List organizations +gh org list + +# List for user +gh org list --user username + +# JSON output +gh org list --json login,name,description + +# View organization +gh org view orgname + +# View organization members +gh org view orgname --json members --jq '.members[] | .login' +``` + +## Search (gh search) + +```bash +# Search code +gh search code "TODO" + +# Search in specific repository +gh search code "TODO" --repo owner/repo + +# Search commits +gh search commits "fix bug" + +# Search issues +gh search issues "label:bug state:open" + +# Search PRs +gh search prs "is:open is:pr review:required" + +# Search repositories +gh search repos "stars:>1000 language:python" + +# Limit results +gh search repos "topic:api" --limit 50 + +# JSON output +gh search repos "stars:>100" --json name,description,stargazers + +# Order results +gh search repos "language:rust" --order desc --sort stars + +# Search with extensions +gh search code "import" --extension py + +# Web search (open in browser) +gh search prs "is:open" --web +``` + +## Labels (gh label) + +```bash +# List labels +gh label list + +# Create label +gh label create bug --color "d73a4a" --description "Something isn't working" + +# Create with hex color +gh label create enhancement --color "#a2eeef" + +# Edit label +gh label edit bug --name "bug-report" --color "ff0000" + +# Delete label +gh label delete bug + +# Clone labels from repository +gh label clone owner/repo + +# Clone to specific repository +gh label clone owner/repo --repo target/repo +``` + +## SSH Keys (gh ssh-key) + +```bash +# List SSH keys +gh ssh-key list + +# Add SSH key +gh ssh-key add ~/.ssh/id_rsa.pub --title "My laptop" + +# Add key with type +gh ssh-key add ~/.ssh/id_ed25519.pub --type "authentication" + +# Delete SSH key +gh ssh-key delete 12345 + +# Delete by title +gh ssh-key delete --title "My laptop" +``` + +## GPG Keys (gh gpg-key) + +```bash +# List GPG keys +gh gpg-key list + +# Add GPG key +gh gpg-key add ~/.ssh/id_rsa.pub + +# Delete GPG key +gh gpg-key delete 12345 + +# Delete by key ID +gh gpg-key delete ABCD1234 +``` + +## Status (gh status) + +```bash +# Show status overview +gh status + +# Status for specific repositories +gh status --repo owner/repo + +# JSON output +gh status --json +``` + +## Configuration (gh config) + +```bash +# List all config +gh config list + +# Get specific value +gh config get editor + +# Set value +gh config set editor vim + +# Set git protocol +gh config set git_protocol ssh + +# Clear cache +gh config clear-cache + +# Set prompt behavior +gh config set prompt disabled +gh config set prompt enabled +``` + +## Extensions (gh extension) + +```bash +# List installed extensions +gh extension list + +# Search extensions +gh extension search github + +# Install extension +gh extension install owner/extension-repo + +# Install from branch +gh extension install owner/extension-repo --branch develop + +# Upgrade extension +gh extension upgrade extension-name + +# Remove extension +gh extension remove extension-name + +# Create new extension +gh extension create my-extension + +# Browse extensions +gh extension browse + +# Execute extension command +gh extension exec my-extension --arg value +``` + +## Aliases (gh alias) + +```bash +# List aliases +gh alias list + +# Set alias +gh alias set prview 'pr view --web' + +# Set shell alias +gh alias set co 'pr checkout' --shell + +# Delete alias +gh alias delete prview + +# Import aliases +gh alias import ./aliases.sh +``` + +## API Requests (gh api) + +```bash +# Make API request +gh api /user + +# Request with method +gh api --method POST /repos/owner/repo/issues \ + --field title="Issue title" \ + --field body="Issue body" + +# Request with headers +gh api /user \ + --header "Accept: application/vnd.github.v3+json" + +# Request with pagination +gh api /user/repos --paginate + +# Raw output (no formatting) +gh api /user --raw + +# Include headers in output +gh api /user --include + +# Silent mode (no progress output) +gh api /user --silent + +# Input from file +gh api --input request.json + +# jq query on response +gh api /user --jq '.login' + +# Field from response +gh api /repos/owner/repo --jq '.stargazers_count' + +# GitHub Enterprise +gh api /user --hostname enterprise.internal + +# GraphQL query +gh api graphql \ + -f query=' + { + viewer { + login + repositories(first: 5) { + nodes { + name + } + } + } + }' +``` + +## Rulesets (gh ruleset) + +```bash +# List rulesets +gh ruleset list + +# View ruleset +gh ruleset view 123 + +# Check ruleset +gh ruleset check --branch feature + +# Check specific repository +gh ruleset check --repo owner/repo --branch main +``` + +## Attestations (gh attestation) + +```bash +# Download attestation +gh attestation download owner/repo \ + --artifact-id 123456 + +# Verify attestation +gh attestation verify owner/repo + +# Get trusted root +gh attestation trusted-root +``` + +## Completion (gh completion) + +```bash +# Generate shell completion +gh completion -s bash > ~/.gh-complete.bash +gh completion -s zsh > ~/.gh-complete.zsh +gh completion -s fish > ~/.gh-complete.fish +gh completion -s powershell > ~/.gh-complete.ps1 + +# Shell-specific instructions +gh completion --shell=bash +gh completion --shell=zsh +``` + +## Preview (gh preview) + +```bash +# List preview features +gh preview + +# Run preview script +gh preview prompter +``` + +## Agent Tasks (gh agent-task) + +```bash +# List agent tasks +gh agent-task list + +# View agent task +gh agent-task view 123 + +# Create agent task +gh agent-task create --description "My task" +``` + +## Global Flags + +| Flag | Description | +| -------------------------- | -------------------------------------- | +| `--help` / `-h` | Show help for command | +| `--version` | Show gh version | +| `--repo [HOST/]OWNER/REPO` | Select another repository | +| `--hostname HOST` | GitHub hostname | +| `--jq EXPRESSION` | Filter JSON output | +| `--json FIELDS` | Output JSON with specified fields | +| `--template STRING` | Format JSON using Go template | +| `--web` | Open in browser | +| `--paginate` | Make additional API calls | +| `--verbose` | Show verbose output | +| `--debug` | Show debug output | +| `--timeout SECONDS` | Maximum API request duration | +| `--cache CACHE` | Cache control (default, force, bypass) | + +## Output Formatting + +### JSON Output + +```bash +# Basic JSON +gh repo view --json name,description + +# Nested fields +gh repo view --json owner,name --jq '.owner.login + "/" + .name' + +# Array operations +gh pr list --json number,title --jq '.[] | select(.number > 100)' + +# Complex queries +gh issue list --json number,title,labels \ + --jq '.[] | {number, title: .title, tags: [.labels[].name]}' +``` + +### Template Output + +```bash +# Custom template +gh repo view \ + --template '{{.name}}: {{.description}}' + +# Multiline template +gh pr view 123 \ + --template 'Title: {{.title}} +Author: {{.author.login}} +State: {{.state}} +' +``` + +## Common Workflows + +### Create PR from Issue + +```bash +# Create branch from issue +gh issue develop 123 --branch feature/issue-123 + +# Make changes, commit, push +git add . +git commit -m "Fix issue #123" +git push + +# Create PR linking to issue +gh pr create --title "Fix #123" --body "Closes #123" +``` + +### Bulk Operations + +```bash +# Close multiple issues +gh issue list --search "label:stale" \ + --json number \ + --jq '.[].number' | \ + xargs -I {} gh issue close {} --comment "Closing as stale" + +# Add label to multiple PRs +gh pr list --search "review:required" \ + --json number \ + --jq '.[].number' | \ + xargs -I {} gh pr edit {} --add-label needs-review +``` + +### Repository Setup Workflow + +```bash +# Create repository with initial setup +gh repo create my-project --public \ + --description "My awesome project" \ + --clone \ + --gitignore python \ + --license mit + +cd my-project + +# Set up branches +git checkout -b develop +git push -u origin develop + +# Create labels +gh label create bug --color "d73a4a" --description "Bug report" +gh label create enhancement --color "a2eeef" --description "Feature request" +gh label create documentation --color "0075ca" --description "Documentation" +``` + +### CI/CD Workflow + +```bash +# Run workflow and wait +RUN_ID=$(gh workflow run ci.yml --ref main --jq '.databaseId') + +# Watch the run +gh run watch "$RUN_ID" + +# Download artifacts on completion +gh run download "$RUN_ID" --dir ./artifacts +``` + +### Fork Sync Workflow + +```bash +# Fork repository +gh repo fork original/repo --clone + +cd repo + +# Add upstream remote +git remote add upstream https://github.com/original/repo.git + +# Sync fork +gh repo sync + +# Or manual sync +git fetch upstream +git checkout main +git merge upstream/main +git push origin main +``` + +## Environment Setup + +### Shell Integration + +```bash +# Add to ~/.bashrc or ~/.zshrc +eval "$(gh completion -s bash)" # or zsh/fish + +# Create useful aliases +alias gs='gh status' +alias gpr='gh pr view --web' +alias gir='gh issue view --web' +alias gco='gh pr checkout' +``` + +### Git Configuration + +```bash +# Use gh as credential helper +gh auth setup-git + +# Set gh as default for repo operations +git config --global credential.helper 'gh !gh auth setup-git' + +# Or manually +git config --global credential.helper github +``` + +## Best Practices + +1. **Authentication**: Use environment variables for automation + + ```bash + export GH_TOKEN=$(gh auth token) + ``` + +2. **Default Repository**: Set default to avoid repetition + + ```bash + gh repo set-default owner/repo + ``` + +3. **JSON Parsing**: Use jq for complex data extraction + + ```bash + gh pr list --json number,title --jq '.[] | select(.title | contains("fix"))' + ``` + +4. **Pagination**: Use --paginate for large result sets + + ```bash + gh issue list --state all --paginate + ``` + +5. **Caching**: Use cache control for frequently accessed data + ```bash + gh api /user --cache force + ``` + +## Getting Help + +```bash +# General help +gh --help + +# Command help +gh pr --help +gh issue create --help + +# Help topics +gh help formatting +gh help environment +gh help exit-codes +gh help accessibility +``` + +## References + +- Official Manual: https://cli.github.com/manual/ +- GitHub Docs: https://docs.github.com/en/github-cli +- REST API: https://docs.github.com/en/rest +- GraphQL API: https://docs.github.com/en/graphql diff --git a/.claude/skills/gh-cli b/.claude/skills/gh-cli new file mode 120000 index 0000000..0026ee7 --- /dev/null +++ b/.claude/skills/gh-cli @@ -0,0 +1 @@ +../../.agents/skills/gh-cli \ No newline at end of file From c9ea8fb8eb6aaf06267d9f9fb5e2019053ca9be6 Mon Sep 17 00:00:00 2001 From: Abid Famasya Date: Fri, 13 Feb 2026 09:58:01 +0700 Subject: [PATCH 3/4] chore: remove out-of-scope gh-cli skill files and add docstrings --- .agents/skills/gh-cli/SKILL.md | 2187 -------------------------------- .claude/skills/gh-cli | 1 - cmd/gdocs-cli/main.go | 2 + 3 files changed, 2 insertions(+), 2188 deletions(-) delete mode 100644 .agents/skills/gh-cli/SKILL.md delete mode 120000 .claude/skills/gh-cli diff --git a/.agents/skills/gh-cli/SKILL.md b/.agents/skills/gh-cli/SKILL.md deleted file mode 100644 index 6756f0b..0000000 --- a/.agents/skills/gh-cli/SKILL.md +++ /dev/null @@ -1,2187 +0,0 @@ ---- -name: gh-cli -description: GitHub CLI (gh) comprehensive reference for repositories, issues, pull requests, Actions, projects, releases, gists, codespaces, organizations, extensions, and all GitHub operations from the command line. ---- - -# GitHub CLI (gh) - -Comprehensive reference for GitHub CLI (gh) - work seamlessly with GitHub from the command line. - -**Version:** 2.85.0 (current as of January 2026) - -## Prerequisites - -### Installation - -```bash -# macOS -brew install gh - -# Linux -curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg -echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null -sudo apt update -sudo apt install gh - -# Windows -winget install --id GitHub.cli - -# Verify installation -gh --version -``` - -### Authentication - -```bash -# Interactive login (default: github.com) -gh auth login - -# Login with specific hostname -gh auth login --hostname enterprise.internal - -# Login with token -gh auth login --with-token < mytoken.txt - -# Check authentication status -gh auth status - -# Switch accounts -gh auth switch --hostname github.com --user username - -# Logout -gh auth logout --hostname github.com --user username -``` - -### Setup Git Integration - -```bash -# Configure git to use gh as credential helper -gh auth setup-git - -# View active token -gh auth token - -# Refresh authentication scopes -gh auth refresh --scopes write:org,read:public_key -``` - -## CLI Structure - -``` -gh # Root command -├── auth # Authentication -│ ├── login -│ ├── logout -│ ├── refresh -│ ├── setup-git -│ ├── status -│ ├── switch -│ └── token -├── browse # Open in browser -├── codespace # GitHub Codespaces -│ ├── code -│ ├── cp -│ ├── create -│ ├── delete -│ ├── edit -│ ├── jupyter -│ ├── list -│ ├── logs -│ ├── ports -│ ├── rebuild -│ ├── ssh -│ ├── stop -│ └── view -├── gist # Gists -│ ├── clone -│ ├── create -│ ├── delete -│ ├── edit -│ ├── list -│ ├── rename -│ └── view -├── issue # Issues -│ ├── create -│ ├── list -│ ├── status -│ ├── close -│ ├── comment -│ ├── delete -│ ├── develop -│ ├── edit -│ ├── lock -│ ├── pin -│ ├── reopen -│ ├── transfer -│ ├── unlock -│ └── view -├── org # Organizations -│ └── list -├── pr # Pull Requests -│ ├── create -│ ├── list -│ ├── status -│ ├── checkout -│ ├── checks -│ ├── close -│ ├── comment -│ ├── diff -│ ├── edit -│ ├── lock -│ ├── merge -│ ├── ready -│ ├── reopen -│ ├── revert -│ ├── review -│ ├── unlock -│ ├── update-branch -│ └── view -├── project # Projects -│ ├── close -│ ├── copy -│ ├── create -│ ├── delete -│ ├── edit -│ ├── field-create -│ ├── field-delete -│ ├── field-list -│ ├── item-add -│ ├── item-archive -│ ├── item-create -│ ├── item-delete -│ ├── item-edit -│ ├── item-list -│ ├── link -│ ├── list -│ ├── mark-template -│ ├── unlink -│ └── view -├── release # Releases -│ ├── create -│ ├── list -│ ├── delete -│ ├── delete-asset -│ ├── download -│ ├── edit -│ ├── upload -│ ├── verify -│ ├── verify-asset -│ └── view -├── repo # Repositories -│ ├── create -│ ├── list -│ ├── archive -│ ├── autolink -│ ├── clone -│ ├── delete -│ ├── deploy-key -│ ├── edit -│ ├── fork -│ ├── gitignore -│ ├── license -│ ├── rename -│ ├── set-default -│ ├── sync -│ ├── unarchive -│ └── view -├── cache # Actions caches -│ ├── delete -│ └── list -├── run # Workflow runs -│ ├── cancel -│ ├── delete -│ ├── download -│ ├── list -│ ├── rerun -│ ├── view -│ └── watch -├── workflow # Workflows -│ ├── disable -│ ├── enable -│ ├── list -│ ├── run -│ └── view -├── agent-task # Agent tasks -├── alias # Command aliases -│ ├── delete -│ ├── import -│ ├── list -│ └── set -├── api # API requests -├── attestation # Artifact attestations -│ ├── download -│ ├── trusted-root -│ └── verify -├── completion # Shell completion -├── config # Configuration -│ ├── clear-cache -│ ├── get -│ ├── list -│ └── set -├── extension # Extensions -│ ├── browse -│ ├── create -│ ├── exec -│ ├── install -│ ├── list -│ ├── remove -│ ├── search -│ └── upgrade -├── gpg-key # GPG keys -│ ├── add -│ ├── delete -│ └── list -├── label # Labels -│ ├── clone -│ ├── create -│ ├── delete -│ ├── edit -│ └── list -├── preview # Preview features -├── ruleset # Rulesets -│ ├── check -│ ├── list -│ └── view -├── search # Search -│ ├── code -│ ├── commits -│ ├── issues -│ ├── prs -│ └── repos -├── secret # Secrets -│ ├── delete -│ ├── list -│ └── set -├── ssh-key # SSH keys -│ ├── add -│ ├── delete -│ └── list -├── status # Status overview -└── variable # Variables - ├── delete - ├── get - ├── list - └── set -``` - -## Configuration - -### Global Configuration - -```bash -# List all configuration -gh config list - -# Get specific configuration value -gh config list git_protocol -gh config get editor - -# Set configuration value -gh config set editor vim -gh config set git_protocol ssh -gh config set prompt disabled -gh config set pager "less -R" - -# Clear configuration cache -gh config clear-cache -``` - -### Environment Variables - -```bash -# GitHub token (for automation) -export GH_TOKEN=ghp_xxxxxxxxxxxx - -# GitHub hostname -export GH_HOST=github.com - -# Disable prompts -export GH_PROMPT_DISABLED=true - -# Custom editor -export GH_EDITOR=vim - -# Custom pager -export GH_PAGER=less - -# HTTP timeout -export GH_TIMEOUT=30 - -# Custom repository (override default) -export GH_REPO=owner/repo - -# Custom git protocol -export GH_ENTERPRISE_HOSTNAME=hostname -``` - -## Authentication (gh auth) - -### Login - -```bash -# Interactive login -gh auth login - -# Web-based authentication -gh auth login --web - -# With clipboard for OAuth code -gh auth login --web --clipboard - -# With specific git protocol -gh auth login --git-protocol ssh - -# With custom hostname (GitHub Enterprise) -gh auth login --hostname enterprise.internal - -# Login with token from stdin -gh auth login --with-token < token.txt - -# Insecure storage (plain text) -gh auth login --insecure-storage -``` - -### Status - -```bash -# Show all authentication status -gh auth status - -# Show active account only -gh auth status --active - -# Show specific hostname -gh auth status --hostname github.com - -# Show token in output -gh auth status --show-token - -# JSON output -gh auth status --json hosts - -# Filter with jq -gh auth status --json hosts --jq '.hosts | add' -``` - -### Switch Accounts - -```bash -# Interactive switch -gh auth switch - -# Switch to specific user/host -gh auth switch --hostname github.com --user monalisa -``` - -### Token - -```bash -# Print authentication token -gh auth token - -# Token for specific host/user -gh auth token --hostname github.com --user monalisa -``` - -### Refresh - -```bash -# Refresh credentials -gh auth refresh - -# Add scopes -gh auth refresh --scopes write:org,read:public_key - -# Remove scopes -gh auth refresh --remove-scopes delete_repo - -# Reset to default scopes -gh auth refresh --reset-scopes - -# With clipboard -gh auth refresh --clipboard -``` - -### Setup Git - -```bash -# Setup git credential helper -gh auth setup-git - -# Setup for specific host -gh auth setup-git --hostname enterprise.internal - -# Force setup even if host not known -gh auth setup-git --hostname enterprise.internal --force -``` - -## Browse (gh browse) - -```bash -# Open repository in browser -gh browse - -# Open specific path -gh browse script/ -gh browse main.go:312 - -# Open issue or PR -gh browse 123 - -# Open commit -gh browse 77507cd94ccafcf568f8560cfecde965fcfa63 - -# Open with specific branch -gh browse main.go --branch bug-fix - -# Open different repository -gh browse --repo owner/repo - -# Open specific pages -gh browse --actions # Actions tab -gh browse --projects # Projects tab -gh browse --releases # Releases tab -gh browse --settings # Settings page -gh browse --wiki # Wiki page - -# Print URL instead of opening -gh browse --no-browser -``` - -## Repositories (gh repo) - -### Create Repository - -```bash -# Create new repository -gh repo create my-repo - -# Create with description -gh repo create my-repo --description "My awesome project" - -# Create public repository -gh repo create my-repo --public - -# Create private repository -gh repo create my-repo --private - -# Create with homepage -gh repo create my-repo --homepage https://example.com - -# Create with license -gh repo create my-repo --license mit - -# Create with gitignore -gh repo create my-repo --gitignore python - -# Initialize as template repository -gh repo create my-repo --template - -# Create repository in organization -gh repo create org/my-repo - -# Create without cloning locally -gh repo create my-repo --source=. - -# Disable issues -gh repo create my-repo --disable-issues - -# Disable wiki -gh repo create my-repo --disable-wiki -``` - -### Clone Repository - -```bash -# Clone repository -gh repo clone owner/repo - -# Clone to specific directory -gh repo clone owner/repo my-directory - -# Clone with different branch -gh repo clone owner/repo --branch develop -``` - -### List Repositories - -```bash -# List all repositories -gh repo list - -# List repositories for owner -gh repo list owner - -# Limit results -gh repo list --limit 50 - -# Public repositories only -gh repo list --public - -# Source repositories only (not forks) -gh repo list --source - -# JSON output -gh repo list --json name,visibility,owner - -# Table output -gh repo list --limit 100 | tail -n +2 - -# Filter with jq -gh repo list --json name --jq '.[].name' -``` - -### View Repository - -```bash -# View repository details -gh repo view - -# View specific repository -gh repo view owner/repo - -# JSON output -gh repo view --json name,description,defaultBranchRef - -# View in browser -gh repo view --web -``` - -### Edit Repository - -```bash -# Edit description -gh repo edit --description "New description" - -# Set homepage -gh repo edit --homepage https://example.com - -# Change visibility -gh repo edit --visibility private -gh repo edit --visibility public - -# Enable/disable features -gh repo edit --enable-issues -gh repo edit --disable-issues -gh repo edit --enable-wiki -gh repo edit --disable-wiki -gh repo edit --enable-projects -gh repo edit --disable-projects - -# Set default branch -gh repo edit --default-branch main - -# Rename repository -gh repo rename new-name - -# Archive repository -gh repo archive -gh repo unarchive -``` - -### Delete Repository - -```bash -# Delete repository -gh repo delete owner/repo - -# Confirm without prompt -gh repo delete owner/repo --yes -``` - -### Fork Repository - -```bash -# Fork repository -gh repo fork owner/repo - -# Fork to organization -gh repo fork owner/repo --org org-name - -# Clone after forking -gh repo fork owner/repo --clone - -# Remote name for fork -gh repo fork owner/repo --remote-name upstream -``` - -### Sync Fork - -```bash -# Sync fork with upstream -gh repo sync - -# Sync specific branch -gh repo sync --branch feature - -# Force sync -gh repo sync --force -``` - -### Set Default Repository - -```bash -# Set default repository for current directory -gh repo set-default - -# Set default explicitly -gh repo set-default owner/repo - -# Unset default -gh repo set-default --unset -``` - -### Repository Autolinks - -```bash -# List autolinks -gh repo autolink list - -# Add autolink -gh repo autolink add \ - --key-prefix JIRA- \ - --url-template https://jira.example.com/browse/ - -# Delete autolink -gh repo autolink delete 12345 -``` - -### Repository Deploy Keys - -```bash -# List deploy keys -gh repo deploy-key list - -# Add deploy key -gh repo deploy-key add ~/.ssh/id_rsa.pub \ - --title "Production server" \ - --read-only - -# Delete deploy key -gh repo deploy-key delete 12345 -``` - -### Gitignore and License - -```bash -# View gitignore template -gh repo gitignore - -# View license template -gh repo license mit - -# License with full name -gh repo license mit --fullname "John Doe" -``` - -## Issues (gh issue) - -### Create Issue - -```bash -# Create issue interactively -gh issue create - -# Create with title -gh issue create --title "Bug: Login not working" - -# Create with title and body -gh issue create \ - --title "Bug: Login not working" \ - --body "Steps to reproduce..." - -# Create with body from file -gh issue create --body-file issue.md - -# Create with labels -gh issue create --title "Fix bug" --labels bug,high-priority - -# Create with assignees -gh issue create --title "Fix bug" --assignee user1,user2 - -# Create in specific repository -gh issue create --repo owner/repo --title "Issue title" - -# Create issue from web -gh issue create --web -``` - -### List Issues - -```bash -# List all open issues -gh issue list - -# List all issues (including closed) -gh issue list --state all - -# List closed issues -gh issue list --state closed - -# Limit results -gh issue list --limit 50 - -# Filter by assignee -gh issue list --assignee username -gh issue list --assignee @me - -# Filter by labels -gh issue list --labels bug,enhancement - -# Filter by milestone -gh issue list --milestone "v1.0" - -# Search/filter -gh issue list --search "is:open is:issue label:bug" - -# JSON output -gh issue list --json number,title,state,author - -# Table view -gh issue list --json number,title,labels --jq '.[] | [.number, .title, .labels[].name] | @tsv' - -# Show comments count -gh issue list --json number,title,comments --jq '.[] | [.number, .title, .comments]' - -# Sort by -gh issue list --sort created --order desc -``` - -### View Issue - -```bash -# View issue -gh issue view 123 - -# View with comments -gh issue view 123 --comments - -# View in browser -gh issue view 123 --web - -# JSON output -gh issue view 123 --json title,body,state,labels,comments - -# View specific fields -gh issue view 123 --json title --jq '.title' -``` - -### Edit Issue - -```bash -# Edit interactively -gh issue edit 123 - -# Edit title -gh issue edit 123 --title "New title" - -# Edit body -gh issue edit 123 --body "New description" - -# Add labels -gh issue edit 123 --add-label bug,high-priority - -# Remove labels -gh issue edit 123 --remove-label stale - -# Add assignees -gh issue edit 123 --add-assignee user1,user2 - -# Remove assignees -gh issue edit 123 --remove-assignee user1 - -# Set milestone -gh issue edit 123 --milestone "v1.0" -``` - -### Close/Reopen Issue - -```bash -# Close issue -gh issue close 123 - -# Close with comment -gh issue close 123 --comment "Fixed in PR #456" - -# Reopen issue -gh issue reopen 123 -``` - -### Comment on Issue - -```bash -# Add comment -gh issue comment 123 --body "This looks good!" - -# Edit comment -gh issue comment 123 --edit 456789 --body "Updated comment" - -# Delete comment -gh issue comment 123 --delete 456789 -``` - -### Issue Status - -```bash -# Show issue status summary -gh issue status - -# Status for specific repository -gh issue status --repo owner/repo -``` - -### Pin/Unpin Issues - -```bash -# Pin issue (pinned to repo dashboard) -gh issue pin 123 - -# Unpin issue -gh issue unpin 123 -``` - -### Lock/Unlock Issue - -```bash -# Lock conversation -gh issue lock 123 - -# Lock with reason -gh issue lock 123 --reason off-topic - -# Unlock -gh issue unlock 123 -``` - -### Transfer Issue - -```bash -# Transfer to another repository -gh issue transfer 123 --repo owner/new-repo -``` - -### Delete Issue - -```bash -# Delete issue -gh issue delete 123 - -# Confirm without prompt -gh issue delete 123 --yes -``` - -### Develop Issue (Draft PR) - -```bash -# Create draft PR from issue -gh issue develop 123 - -# Create in specific branch -gh issue develop 123 --branch fix/issue-123 - -# Create with base branch -gh issue develop 123 --base main -``` - -## Pull Requests (gh pr) - -### Create Pull Request - -```bash -# Create PR interactively -gh pr create - -# Create with title -gh pr create --title "Feature: Add new functionality" - -# Create with title and body -gh pr create \ - --title "Feature: Add new functionality" \ - --body "This PR adds..." - -# Fill body from template -gh pr create --body-file .github/PULL_REQUEST_TEMPLATE.md - -# Set base branch -gh pr create --base main - -# Set head branch (default: current branch) -gh pr create --head feature-branch - -# Create draft PR -gh pr create --draft - -# Add assignees -gh pr create --assignee user1,user2 - -# Add reviewers -gh pr create --reviewer user1,user2 - -# Add labels -gh pr create --labels enhancement,feature - -# Link to issue -gh pr create --issue 123 - -# Create in specific repository -gh pr create --repo owner/repo - -# Open in browser after creation -gh pr create --web -``` - -### List Pull Requests - -```bash -# List open PRs -gh pr list - -# List all PRs -gh pr list --state all - -# List merged PRs -gh pr list --state merged - -# List closed (not merged) PRs -gh pr list --state closed - -# Filter by head branch -gh pr list --head feature-branch - -# Filter by base branch -gh pr list --base main - -# Filter by author -gh pr list --author username -gh pr list --author @me - -# Filter by assignee -gh pr list --assignee username - -# Filter by labels -gh pr list --labels bug,enhancement - -# Limit results -gh pr list --limit 50 - -# Search -gh pr list --search "is:open is:pr label:review-required" - -# JSON output -gh pr list --json number,title,state,author,headRefName - -# Show check status -gh pr list --json number,title,statusCheckRollup --jq '.[] | [.number, .title, .statusCheckRollup[]?.status]' - -# Sort by -gh pr list --sort created --order desc -``` - -### View Pull Request - -```bash -# View PR -gh pr view 123 - -# View with comments -gh pr view 123 --comments - -# View in browser -gh pr view 123 --web - -# JSON output -gh pr view 123 --json title,body,state,author,commits,files - -# View diff -gh pr view 123 --json files --jq '.files[].path' - -# View with jq query -gh pr view 123 --json title,state --jq '"\(.title): \(.state)"' -``` - -### Checkout Pull Request - -```bash -# Checkout PR branch -gh pr checkout 123 - -# Checkout with specific branch name -gh pr checkout 123 --branch name-123 - -# Force checkout -gh pr checkout 123 --force -``` - -### Diff Pull Request - -```bash -# View PR diff -gh pr diff 123 - -# View diff with color -gh pr diff 123 --color always - -# Output to file -gh pr diff 123 > pr-123.patch - -# View diff of specific files -gh pr diff 123 --name-only -``` - -### Merge Pull Request - -```bash -# Merge PR -gh pr merge 123 - -# Merge with specific method -gh pr merge 123 --merge -gh pr merge 123 --squash -gh pr merge 123 --rebase - -# Delete branch after merge -gh pr merge 123 --delete-branch - -# Merge with comment -gh pr merge 123 --subject "Merge PR #123" --body "Merging feature" - -# Merge draft PR -gh pr merge 123 --admin - -# Force merge (skip checks) -gh pr merge 123 --admin -``` - -### Close Pull Request - -```bash -# Close PR (as draft, not merge) -gh pr close 123 - -# Close with comment -gh pr close 123 --comment "Closing due to..." -``` - -### Reopen Pull Request - -```bash -# Reopen closed PR -gh pr reopen 123 -``` - -### Edit Pull Request - -```bash -# Edit interactively -gh pr edit 123 - -# Edit title -gh pr edit 123 --title "New title" - -# Edit body -gh pr edit 123 --body "New description" - -# Add labels -gh pr edit 123 --add-label bug,enhancement - -# Remove labels -gh pr edit 123 --remove-label stale - -# Add assignees -gh pr edit 123 --add-assignee user1,user2 - -# Remove assignees -gh pr edit 123 --remove-assignee user1 - -# Add reviewers -gh pr edit 123 --add-reviewer user1,user2 - -# Remove reviewers -gh pr edit 123 --remove-reviewer user1 - -# Mark as ready for review -gh pr edit 123 --ready -``` - -### Ready for Review - -```bash -# Mark draft PR as ready -gh pr ready 123 -``` - -### Pull Request Checks - -```bash -# View PR checks -gh pr checks 123 - -# Watch checks in real-time -gh pr checks 123 --watch - -# Watch interval (seconds) -gh pr checks 123 --watch --interval 5 -``` - -### Comment on Pull Request - -```bash -# Add comment -gh pr comment 123 --body "Looks good!" - -# Comment on specific line -gh pr comment 123 --body "Fix this" \ - --repo owner/repo \ - --head-owner owner --head-branch feature - -# Edit comment -gh pr comment 123 --edit 456789 --body "Updated" - -# Delete comment -gh pr comment 123 --delete 456789 -``` - -### Review Pull Request - -```bash -# Review PR (opens editor) -gh pr review 123 - -# Approve PR -gh pr review 123 --approve --body "LGTM!" - -# Request changes -gh pr review 123 --request-changes \ - --body "Please fix these issues" - -# Comment on PR -gh pr review 123 --comment --body "Some thoughts..." - -# Dismiss review -gh pr review 123 --dismiss -``` - -### Update Branch - -```bash -# Update PR branch with latest base branch -gh pr update-branch 123 - -# Force update -gh pr update-branch 123 --force - -# Use merge strategy -gh pr update-branch 123 --merge -``` - -### Lock/Unlock Pull Request - -```bash -# Lock PR conversation -gh pr lock 123 - -# Lock with reason -gh pr lock 123 --reason off-topic - -# Unlock -gh pr unlock 123 -``` - -### Revert Pull Request - -```bash -# Revert merged PR -gh pr revert 123 - -# Revert with specific branch name -gh pr revert 123 --branch revert-pr-123 -``` - -### Pull Request Status - -```bash -# Show PR status summary -gh pr status - -# Status for specific repository -gh pr status --repo owner/repo -``` - -## GitHub Actions - -### Workflow Runs (gh run) - -```bash -# List workflow runs -gh run list - -# List for specific workflow -gh run list --workflow "ci.yml" - -# List for specific branch -gh run list --branch main - -# Limit results -gh run list --limit 20 - -# JSON output -gh run list --json databaseId,status,conclusion,headBranch - -# View run details -gh run view 123456789 - -# View run with verbose logs -gh run view 123456789 --log - -# View specific job -gh run view 123456789 --job 987654321 - -# View in browser -gh run view 123456789 --web - -# Watch run in real-time -gh run watch 123456789 - -# Watch with interval -gh run watch 123456789 --interval 5 - -# Rerun failed run -gh run rerun 123456789 - -# Rerun specific job -gh run rerun 123456789 --job 987654321 - -# Cancel run -gh run cancel 123456789 - -# Delete run -gh run delete 123456789 - -# Download run artifacts -gh run download 123456789 - -# Download specific artifact -gh run download 123456789 --name build - -# Download to directory -gh run download 123456789 --dir ./artifacts -``` - -### Workflows (gh workflow) - -```bash -# List workflows -gh workflow list - -# View workflow details -gh workflow view ci.yml - -# View workflow YAML -gh workflow view ci.yml --yaml - -# View in browser -gh workflow view ci.yml --web - -# Enable workflow -gh workflow enable ci.yml - -# Disable workflow -gh workflow disable ci.yml - -# Run workflow manually -gh workflow run ci.yml - -# Run with inputs -gh workflow run ci.yml \ - --raw-field \ - version="1.0.0" \ - environment="production" - -# Run from specific branch -gh workflow run ci.yml --ref develop -``` - -### Action Caches (gh cache) - -```bash -# List caches -gh cache list - -# List for specific branch -gh cache list --branch main - -# List with limit -gh cache list --limit 50 - -# Delete cache -gh cache delete 123456789 - -# Delete all caches -gh cache delete --all -``` - -### Action Secrets (gh secret) - -```bash -# List secrets -gh secret list - -# Set secret (prompts for value) -gh secret set MY_SECRET - -# Set secret from environment -echo "$MY_SECRET" | gh secret set MY_SECRET - -# Set secret for specific environment -gh secret set MY_SECRET --env production - -# Set secret for organization -gh secret set MY_SECRET --org orgname - -# Delete secret -gh secret delete MY_SECRET - -# Delete from environment -gh secret delete MY_SECRET --env production -``` - -### Action Variables (gh variable) - -```bash -# List variables -gh variable list - -# Set variable -gh variable set MY_VAR "some-value" - -# Set variable for environment -gh variable set MY_VAR "value" --env production - -# Set variable for organization -gh variable set MY_VAR "value" --org orgname - -# Get variable value -gh variable get MY_VAR - -# Delete variable -gh variable delete MY_VAR - -# Delete from environment -gh variable delete MY_VAR --env production -``` - -## Projects (gh project) - -```bash -# List projects -gh project list - -# List for owner -gh project list --owner owner - -# Open projects -gh project list --open - -# View project -gh project view 123 - -# View project items -gh project view 123 --format json - -# Create project -gh project create --title "My Project" - -# Create in organization -gh project create --title "Project" --org orgname - -# Create with readme -gh project create --title "Project" --readme "Description here" - -# Edit project -gh project edit 123 --title "New Title" - -# Delete project -gh project delete 123 - -# Close project -gh project close 123 - -# Copy project -gh project copy 123 --owner target-owner --title "Copy" - -# Mark template -gh project mark-template 123 - -# List fields -gh project field-list 123 - -# Create field -gh project field-create 123 --title "Status" --datatype single_select - -# Delete field -gh project field-delete 123 --id 456 - -# List items -gh project item-list 123 - -# Create item -gh project item-create 123 --title "New item" - -# Add item to project -gh project item-add 123 --owner-owner --repo repo --issue 456 - -# Edit item -gh project item-edit 123 --id 456 --title "Updated title" - -# Delete item -gh project item-delete 123 --id 456 - -# Archive item -gh project item-archive 123 --id 456 - -# Link items -gh project link 123 --id 456 --link-id 789 - -# Unlink items -gh project unlink 123 --id 456 --link-id 789 - -# View project in browser -gh project view 123 --web -``` - -## Releases (gh release) - -```bash -# List releases -gh release list - -# View latest release -gh release view - -# View specific release -gh release view v1.0.0 - -# View in browser -gh release view v1.0.0 --web - -# Create release -gh release create v1.0.0 \ - --notes "Release notes here" - -# Create release with notes from file -gh release create v1.0.0 --notes-file notes.md - -# Create release with target -gh release create v1.0.0 --target main - -# Create release as draft -gh release create v1.0.0 --draft - -# Create pre-release -gh release create v1.0.0 --prerelease - -# Create release with title -gh release create v1.0.0 --title "Version 1.0.0" - -# Upload asset to release -gh release upload v1.0.0 ./file.tar.gz - -# Upload multiple assets -gh release upload v1.0.0 ./file1.tar.gz ./file2.tar.gz - -# Upload with label (casing sensitive) -gh release upload v1.0.0 ./file.tar.gz --casing - -# Delete release -gh release delete v1.0.0 - -# Delete with cleanup tag -gh release delete v1.0.0 --yes - -# Delete specific asset -gh release delete-asset v1.0.0 file.tar.gz - -# Download release assets -gh release download v1.0.0 - -# Download specific asset -gh release download v1.0.0 --pattern "*.tar.gz" - -# Download to directory -gh release download v1.0.0 --dir ./downloads - -# Download archive (zip/tar) -gh release download v1.0.0 --archive zip - -# Edit release -gh release edit v1.0.0 --notes "Updated notes" - -# Verify release signature -gh release verify v1.0.0 - -# Verify specific asset -gh release verify-asset v1.0.0 file.tar.gz -``` - -## Gists (gh gist) - -```bash -# List gists -gh gist list - -# List all gists (including private) -gh gist list --public - -# Limit results -gh gist list --limit 20 - -# View gist -gh gist view abc123 - -# View gist files -gh gist view abc123 --files - -# Create gist -gh gist create script.py - -# Create gist with description -gh gist create script.py --desc "My script" - -# Create public gist -gh gist create script.py --public - -# Create multi-file gist -gh gist create file1.py file2.py - -# Create from stdin -echo "print('hello')" | gh gist create - -# Edit gist -gh gist edit abc123 - -# Delete gist -gh gist delete abc123 - -# Rename gist file -gh gist rename abc123 --filename old.py new.py - -# Clone gist -gh gist clone abc123 - -# Clone to directory -gh gist clone abc123 my-directory -``` - -## Codespaces (gh codespace) - -```bash -# List codespaces -gh codespace list - -# Create codespace -gh codespace create - -# Create with specific repository -gh codespace create --repo owner/repo - -# Create with branch -gh codespace create --branch develop - -# Create with specific machine -gh codespace create --machine premiumLinux - -# View codespace details -gh codespace view - -# SSH into codespace -gh codespace ssh - -# SSH with specific command -gh codespace ssh --command "cd /workspaces && ls" - -# Open codespace in browser -gh codespace code - -# Open in VS Code -gh codespace code --codec - -# Open with specific path -gh codespace code --path /workspaces/repo - -# Stop codespace -gh codespace stop - -# Delete codespace -gh codespace delete - -# View logs -gh codespace logs - ---tail 100 - -# View ports -gh codespace ports - -# Forward port -gh codespace cp 8080:8080 - -# Rebuild codespace -gh codespace rebuild - -# Edit codespace -gh codespace edit --machine standardLinux - -# Jupyter support -gh codespace jupyter - -# Copy files to/from codespace -gh codespace cp file.txt :/workspaces/file.txt -gh codespace cp :/workspaces/file.txt ./file.txt -``` - -## Organizations (gh org) - -```bash -# List organizations -gh org list - -# List for user -gh org list --user username - -# JSON output -gh org list --json login,name,description - -# View organization -gh org view orgname - -# View organization members -gh org view orgname --json members --jq '.members[] | .login' -``` - -## Search (gh search) - -```bash -# Search code -gh search code "TODO" - -# Search in specific repository -gh search code "TODO" --repo owner/repo - -# Search commits -gh search commits "fix bug" - -# Search issues -gh search issues "label:bug state:open" - -# Search PRs -gh search prs "is:open is:pr review:required" - -# Search repositories -gh search repos "stars:>1000 language:python" - -# Limit results -gh search repos "topic:api" --limit 50 - -# JSON output -gh search repos "stars:>100" --json name,description,stargazers - -# Order results -gh search repos "language:rust" --order desc --sort stars - -# Search with extensions -gh search code "import" --extension py - -# Web search (open in browser) -gh search prs "is:open" --web -``` - -## Labels (gh label) - -```bash -# List labels -gh label list - -# Create label -gh label create bug --color "d73a4a" --description "Something isn't working" - -# Create with hex color -gh label create enhancement --color "#a2eeef" - -# Edit label -gh label edit bug --name "bug-report" --color "ff0000" - -# Delete label -gh label delete bug - -# Clone labels from repository -gh label clone owner/repo - -# Clone to specific repository -gh label clone owner/repo --repo target/repo -``` - -## SSH Keys (gh ssh-key) - -```bash -# List SSH keys -gh ssh-key list - -# Add SSH key -gh ssh-key add ~/.ssh/id_rsa.pub --title "My laptop" - -# Add key with type -gh ssh-key add ~/.ssh/id_ed25519.pub --type "authentication" - -# Delete SSH key -gh ssh-key delete 12345 - -# Delete by title -gh ssh-key delete --title "My laptop" -``` - -## GPG Keys (gh gpg-key) - -```bash -# List GPG keys -gh gpg-key list - -# Add GPG key -gh gpg-key add ~/.ssh/id_rsa.pub - -# Delete GPG key -gh gpg-key delete 12345 - -# Delete by key ID -gh gpg-key delete ABCD1234 -``` - -## Status (gh status) - -```bash -# Show status overview -gh status - -# Status for specific repositories -gh status --repo owner/repo - -# JSON output -gh status --json -``` - -## Configuration (gh config) - -```bash -# List all config -gh config list - -# Get specific value -gh config get editor - -# Set value -gh config set editor vim - -# Set git protocol -gh config set git_protocol ssh - -# Clear cache -gh config clear-cache - -# Set prompt behavior -gh config set prompt disabled -gh config set prompt enabled -``` - -## Extensions (gh extension) - -```bash -# List installed extensions -gh extension list - -# Search extensions -gh extension search github - -# Install extension -gh extension install owner/extension-repo - -# Install from branch -gh extension install owner/extension-repo --branch develop - -# Upgrade extension -gh extension upgrade extension-name - -# Remove extension -gh extension remove extension-name - -# Create new extension -gh extension create my-extension - -# Browse extensions -gh extension browse - -# Execute extension command -gh extension exec my-extension --arg value -``` - -## Aliases (gh alias) - -```bash -# List aliases -gh alias list - -# Set alias -gh alias set prview 'pr view --web' - -# Set shell alias -gh alias set co 'pr checkout' --shell - -# Delete alias -gh alias delete prview - -# Import aliases -gh alias import ./aliases.sh -``` - -## API Requests (gh api) - -```bash -# Make API request -gh api /user - -# Request with method -gh api --method POST /repos/owner/repo/issues \ - --field title="Issue title" \ - --field body="Issue body" - -# Request with headers -gh api /user \ - --header "Accept: application/vnd.github.v3+json" - -# Request with pagination -gh api /user/repos --paginate - -# Raw output (no formatting) -gh api /user --raw - -# Include headers in output -gh api /user --include - -# Silent mode (no progress output) -gh api /user --silent - -# Input from file -gh api --input request.json - -# jq query on response -gh api /user --jq '.login' - -# Field from response -gh api /repos/owner/repo --jq '.stargazers_count' - -# GitHub Enterprise -gh api /user --hostname enterprise.internal - -# GraphQL query -gh api graphql \ - -f query=' - { - viewer { - login - repositories(first: 5) { - nodes { - name - } - } - } - }' -``` - -## Rulesets (gh ruleset) - -```bash -# List rulesets -gh ruleset list - -# View ruleset -gh ruleset view 123 - -# Check ruleset -gh ruleset check --branch feature - -# Check specific repository -gh ruleset check --repo owner/repo --branch main -``` - -## Attestations (gh attestation) - -```bash -# Download attestation -gh attestation download owner/repo \ - --artifact-id 123456 - -# Verify attestation -gh attestation verify owner/repo - -# Get trusted root -gh attestation trusted-root -``` - -## Completion (gh completion) - -```bash -# Generate shell completion -gh completion -s bash > ~/.gh-complete.bash -gh completion -s zsh > ~/.gh-complete.zsh -gh completion -s fish > ~/.gh-complete.fish -gh completion -s powershell > ~/.gh-complete.ps1 - -# Shell-specific instructions -gh completion --shell=bash -gh completion --shell=zsh -``` - -## Preview (gh preview) - -```bash -# List preview features -gh preview - -# Run preview script -gh preview prompter -``` - -## Agent Tasks (gh agent-task) - -```bash -# List agent tasks -gh agent-task list - -# View agent task -gh agent-task view 123 - -# Create agent task -gh agent-task create --description "My task" -``` - -## Global Flags - -| Flag | Description | -| -------------------------- | -------------------------------------- | -| `--help` / `-h` | Show help for command | -| `--version` | Show gh version | -| `--repo [HOST/]OWNER/REPO` | Select another repository | -| `--hostname HOST` | GitHub hostname | -| `--jq EXPRESSION` | Filter JSON output | -| `--json FIELDS` | Output JSON with specified fields | -| `--template STRING` | Format JSON using Go template | -| `--web` | Open in browser | -| `--paginate` | Make additional API calls | -| `--verbose` | Show verbose output | -| `--debug` | Show debug output | -| `--timeout SECONDS` | Maximum API request duration | -| `--cache CACHE` | Cache control (default, force, bypass) | - -## Output Formatting - -### JSON Output - -```bash -# Basic JSON -gh repo view --json name,description - -# Nested fields -gh repo view --json owner,name --jq '.owner.login + "/" + .name' - -# Array operations -gh pr list --json number,title --jq '.[] | select(.number > 100)' - -# Complex queries -gh issue list --json number,title,labels \ - --jq '.[] | {number, title: .title, tags: [.labels[].name]}' -``` - -### Template Output - -```bash -# Custom template -gh repo view \ - --template '{{.name}}: {{.description}}' - -# Multiline template -gh pr view 123 \ - --template 'Title: {{.title}} -Author: {{.author.login}} -State: {{.state}} -' -``` - -## Common Workflows - -### Create PR from Issue - -```bash -# Create branch from issue -gh issue develop 123 --branch feature/issue-123 - -# Make changes, commit, push -git add . -git commit -m "Fix issue #123" -git push - -# Create PR linking to issue -gh pr create --title "Fix #123" --body "Closes #123" -``` - -### Bulk Operations - -```bash -# Close multiple issues -gh issue list --search "label:stale" \ - --json number \ - --jq '.[].number' | \ - xargs -I {} gh issue close {} --comment "Closing as stale" - -# Add label to multiple PRs -gh pr list --search "review:required" \ - --json number \ - --jq '.[].number' | \ - xargs -I {} gh pr edit {} --add-label needs-review -``` - -### Repository Setup Workflow - -```bash -# Create repository with initial setup -gh repo create my-project --public \ - --description "My awesome project" \ - --clone \ - --gitignore python \ - --license mit - -cd my-project - -# Set up branches -git checkout -b develop -git push -u origin develop - -# Create labels -gh label create bug --color "d73a4a" --description "Bug report" -gh label create enhancement --color "a2eeef" --description "Feature request" -gh label create documentation --color "0075ca" --description "Documentation" -``` - -### CI/CD Workflow - -```bash -# Run workflow and wait -RUN_ID=$(gh workflow run ci.yml --ref main --jq '.databaseId') - -# Watch the run -gh run watch "$RUN_ID" - -# Download artifacts on completion -gh run download "$RUN_ID" --dir ./artifacts -``` - -### Fork Sync Workflow - -```bash -# Fork repository -gh repo fork original/repo --clone - -cd repo - -# Add upstream remote -git remote add upstream https://github.com/original/repo.git - -# Sync fork -gh repo sync - -# Or manual sync -git fetch upstream -git checkout main -git merge upstream/main -git push origin main -``` - -## Environment Setup - -### Shell Integration - -```bash -# Add to ~/.bashrc or ~/.zshrc -eval "$(gh completion -s bash)" # or zsh/fish - -# Create useful aliases -alias gs='gh status' -alias gpr='gh pr view --web' -alias gir='gh issue view --web' -alias gco='gh pr checkout' -``` - -### Git Configuration - -```bash -# Use gh as credential helper -gh auth setup-git - -# Set gh as default for repo operations -git config --global credential.helper 'gh !gh auth setup-git' - -# Or manually -git config --global credential.helper github -``` - -## Best Practices - -1. **Authentication**: Use environment variables for automation - - ```bash - export GH_TOKEN=$(gh auth token) - ``` - -2. **Default Repository**: Set default to avoid repetition - - ```bash - gh repo set-default owner/repo - ``` - -3. **JSON Parsing**: Use jq for complex data extraction - - ```bash - gh pr list --json number,title --jq '.[] | select(.title | contains("fix"))' - ``` - -4. **Pagination**: Use --paginate for large result sets - - ```bash - gh issue list --state all --paginate - ``` - -5. **Caching**: Use cache control for frequently accessed data - ```bash - gh api /user --cache force - ``` - -## Getting Help - -```bash -# General help -gh --help - -# Command help -gh pr --help -gh issue create --help - -# Help topics -gh help formatting -gh help environment -gh help exit-codes -gh help accessibility -``` - -## References - -- Official Manual: https://cli.github.com/manual/ -- GitHub Docs: https://docs.github.com/en/github-cli -- REST API: https://docs.github.com/en/rest -- GraphQL API: https://docs.github.com/en/graphql diff --git a/.claude/skills/gh-cli b/.claude/skills/gh-cli deleted file mode 120000 index 0026ee7..0000000 --- a/.claude/skills/gh-cli +++ /dev/null @@ -1 +0,0 @@ -../../.agents/skills/gh-cli \ No newline at end of file diff --git a/cmd/gdocs-cli/main.go b/cmd/gdocs-cli/main.go index 8b99ca7..b152d20 100644 --- a/cmd/gdocs-cli/main.go +++ b/cmd/gdocs-cli/main.go @@ -73,6 +73,8 @@ func main() { } } +// run executes the main logic of the CLI. +// It handles authentication, document fetching, and markdown conversion. func run(docURL, credPath string, includeComments bool) error { ctx := context.Background() From caa24046ec46692bb7b076ab1f419c9687b967e2 Mon Sep 17 00:00:00 2001 From: Abid Famasya Date: Fri, 13 Feb 2026 10:02:18 +0700 Subject: [PATCH 4/4] fix: address CodeRabbit review comments - Add context to Drive API calls in FetchComments - Add blank line before comments section in converter - Escape markdown special chars in author names - Update README to reflect comments feature status --- README.md | 4 ++-- internal/gdocs/comments.go | 2 +- internal/markdown/comments.go | 8 ++++++++ internal/markdown/converter.go | 1 + 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 5b5ed0d..39f7c1a 100644 --- a/README.md +++ b/README.md @@ -230,7 +230,7 @@ modified: (if available) --- ``` -**Note:** The Google Docs API v1 doesn't provide author or date information. These fields may be empty unless fetched from Google Drive API. +**Note:** The Google Docs API v1 doesn't provide author or date information for the document. These fields may be empty in the frontmatter unless fetched from Google Drive API. Comments are supported via `--comments` flag (see below). ## Known Limitations @@ -239,7 +239,7 @@ modified: (if available) - **Drawings:** Not supported - will be skipped - **Equations:** Not supported - will be skipped - **Comments:** Supported via `--comments` flag (requires Drive API scope, see below) -- **Metadata:** Author and dates require Google Drive API (not implemented in this version) +- **Metadata:** Author and dates in frontmatter are not yet extracted (comments via Drive API are supported) ## Troubleshooting diff --git a/internal/gdocs/comments.go b/internal/gdocs/comments.go index f97e84e..29bb826 100644 --- a/internal/gdocs/comments.go +++ b/internal/gdocs/comments.go @@ -36,7 +36,7 @@ func FetchComments(ctx context.Context, httpClient *http.Client, docID string) ( var comments []Comment pageToken := "" for { - call := srv.Comments.List(docID).Fields("comments(author(displayName),content,quotedFileContent,createdTime,resolved,replies(author(displayName),content,createdTime)),nextPageToken").PageSize(100) + call := srv.Comments.List(docID).Fields("comments(author(displayName),content,quotedFileContent,createdTime,resolved,replies(author(displayName),content,createdTime)),nextPageToken").PageSize(100).Context(ctx) if pageToken != "" { call = call.PageToken(pageToken) } diff --git a/internal/markdown/comments.go b/internal/markdown/comments.go index acc4a67..fa02105 100644 --- a/internal/markdown/comments.go +++ b/internal/markdown/comments.go @@ -28,6 +28,7 @@ func ConvertComments(comments []gdocs.Comment) string { if author == "" { author = "Unknown" } + author = escapeMarkdown(author) builder.WriteString(fmt.Sprintf("**%s**", author)) if ts := formatTime(c.CreatedTime); ts != "" { builder.WriteString(fmt.Sprintf(" (%s)", ts)) @@ -44,6 +45,7 @@ func ConvertComments(comments []gdocs.Comment) string { if rAuthor == "" { rAuthor = "Unknown" } + rAuthor = escapeMarkdown(rAuthor) builder.WriteString(fmt.Sprintf(" ↳ **%s**", rAuthor)) if ts := formatTime(r.CreatedTime); ts != "" { builder.WriteString(fmt.Sprintf(" (%s)", ts)) @@ -70,3 +72,9 @@ func formatTime(rfc3339 string) string { } return t.Format("2006-01-02") } + +func escapeMarkdown(s string) string { + s = strings.ReplaceAll(s, "*", "\\*") + s = strings.ReplaceAll(s, "_", "\\_") + return s +} diff --git a/internal/markdown/converter.go b/internal/markdown/converter.go index 913f09a..6850234 100644 --- a/internal/markdown/converter.go +++ b/internal/markdown/converter.go @@ -77,6 +77,7 @@ func (c *Converter) Convert() (string, error) { // Append comments if present if len(c.comments) > 0 { + builder.WriteString("\n") builder.WriteString(ConvertComments(c.comments)) }