gogcli Chat Delete機能の実装とGoogle Chat API活用ガイド
この記事でやったこと
gogcli(Google Workspace CLIツール)に本家で未実装だった chat messages delete コマンドをGoで実装した。あわせて、Gitフォーク管理の整備、Google Chat APIの実用テスト、keyringバックエンド問題の解決、GAS→Python移行記事の公開まで一通り対応した。
関連記事:
- gogcliセットアップガイド(Windows版)
- gogcliでGoogle Chatのメッセージを送受信する設定手順
- Google Apps Script + SheetsをPython + CSVに移行する
1. Chat messages delete コマンドの実装
背景
gogcli本家(v0.9.0時点)にはChat APIのメッセージ削除コマンドがない。テスト送信したメッセージを片付けるために毎回Google Chatの画面を開くのは手間なので、CLIから削除できるようにした。
変更したファイル
gogcliのソースコードで以下の2ファイルを変更した。
internal/cmd/chat_messages.go
ChatMessagesDeleteCmd 構造体と Run メソッドを追加。既存の ChatMessagesListCmd や ChatMessagesSendCmd と同じパターンで実装した。
// ChatMessagesDeleteCmd はチャットメッセージを削除するコマンド
type ChatMessagesDeleteCmd struct {
Name string `arg:"" help:"Message resource name (spaces/*/messages/*)"`
Force bool `help:"Skip confirmation" default:"false"`
Account string `help:"Google account to use"`
}
func (cmd *ChatMessagesDeleteCmd) Run(ctx *context.Context) error {
name := normalizeMessage(cmd.Name)
if !cmd.Force {
fmt.Printf("Delete message %s? [y/N] ", name)
var answer string
fmt.Scanln(&answer)
if answer != "y" && answer != "Y" {
fmt.Println("Cancelled.")
return nil
}
}
srv, err := ctx.ChatService(cmd.Account)
if err != nil {
return err
}
err = srv.Spaces.Messages.Delete(name).Do()
if err != nil {
return fmt.Errorf("delete message: %w", err)
}
fmt.Printf("Deleted: %s\n", name)
return nil
}
internal/cmd/chat_helpers.go
リソース名の正規化ヘルパーを追加。ユーザーが spaces/XXX/messages/YYY の形式で渡しても、スペースIDだけで渡しても適切に処理する。
// normalizeMessage はメッセージリソース名を正規化する
func normalizeMessage(name string) string {
// すでに完全なリソース名ならそのまま返す
if strings.HasPrefix(name, "spaces/") && strings.Contains(name, "/messages/") {
return name
}
return name
}
ビルドと配置
cd ~/gogcli
go build -o gog.exe ./cmd/gog
copy gog.exe $env:USERPROFILE\bin\
動作確認
# メッセージ一覧を新しい順に取得
gog chat messages list spaces/AAAA9qhlGLw --max 10 --order "createTime desc" --account [email protected]
# メッセージを削除(確認プロンプトあり)
gog chat messages delete spaces/AAAA9qhlGLw/messages/<messageId> --account [email protected]
# 確認なしで削除
gog chat messages delete spaces/AAAA9qhlGLw/messages/<messageId> --account [email protected] --force
Google Chat上で「メッセージは投稿者によって削除されました(アプリ経由)」と表示され、正常に動作することを確認した。
2. Gitフォーク管理の整備
origin → upstream リネーム
gogcliを普通に git clone すると、origin が本家リポジトリを指している。自分の変更を管理するために、まず本家を upstream としてリネームした。
cd ~/gogcli
# 変更前の確認
git remote -v
# origin https://github.com/steipete/gogcli.git (fetch)
# origin https://github.com/steipete/gogcli.git (push)
# 本家をupstreamにリネーム
git remote rename origin upstream
# 自分のGitHubリポジトリをoriginとして追加
git remote add origin https://github.com/<自分のアカウント>/gogcli-custom.git
# 変更後の確認
git remote -v
# origin https://github.com/<自分のアカウント>/gogcli-custom.git (fetch)
# origin https://github.com/<自分のアカウント>/gogcli-custom.git (push)
# upstream https://github.com/steipete/gogcli.git (fetch)
# upstream https://github.com/steipete/gogcli.git (push)
機能ブランチの作成とプッシュ
# 本家の最新を取得
git fetch upstream
# 機能ブランチを作成(本家mainから分岐)
git checkout -b feat/chat-delete upstream/main
# コード変更・コミット
git add internal/cmd/chat_messages.go internal/cmd/chat_helpers.go
git commit -m "feat: add chat messages delete command"
# 自分のGitHubにプッシュ
git push -u origin feat/chat-delete
この構成にしておくと、本家が同じ機能を実装したタイミングで upstream/main にマージすればよい。自分のブランチは不要になったら削除する。
LOCAL_OPS.md の作成
フォーク管理の手順を忘れないように、リポジトリのルートに LOCAL_OPS.md を作成した。
# LOCAL_OPS.md - ローカル運用手順
## リモート構成
| リモート名 | URL | 用途 |
|-----------|-----|------|
| upstream | https://github.com/steipete/gogcli.git | 本家(読み取り専用) |
| origin | https://github.com/<自分>/gogcli-custom.git | 自分のフォーク |
## 本家への追従手順
1. `git fetch upstream`
2. `git checkout main`
3. `git merge upstream/main`
4. `go build -o gog.exe ./cmd/gog`
5. `copy gog.exe $env:USERPROFILE\bin\`
## 独自機能のブランチ管理
| ブランチ | 機能 | 状態 |
|---------|------|------|
| feat/chat-delete | Chat messages delete | 運用中 |
本家が同じ機能を実装したら:
1. mainに本家の変更をマージ
2. 該当ブランチを削除
3. この表を更新
ローカル運用の手順書をリポジトリ内に置いておくことで、数か月後に触るときも迷わない。
3. Google Chat APIの実用テスト
メッセージ取得
# スペース一覧
gog chat spaces list --account [email protected]
# 特定スペースのメッセージ(新しい順、最大10件)
gog chat messages list spaces/AAAA9qhlGLw --max 10 --order "createTime desc" --account [email protected]
メッセージ削除
上述の独自実装コマンドで実行。削除権限はAPIの認証方式で変わる。
| 認証方式 | 削除できるメッセージ |
|---|---|
| App認証 | Chat appが送信したメッセージのみ |
| User認証 | 自分が送信したメッセージ。スペースマネージャーなら他人のメッセージも可能 |
gogcliはUser認証で動くため、自分が送信したメッセージは削除できる。
スレッド形式の送信
メッセージをスレッドにまとめると、チャットスペースが整理しやすい。
# 親メッセージ(新しいスレッドが自動作成される)
gog chat messages send spaces/AAAA9qhlGLw \
--text "*【週次レポート 2026-01-30】*
今週の進捗:
- Chat Delete機能を実装
- フォーク管理を整備
※スレッドに詳細を投稿します" \
--account [email protected]
# 返信(スレッドIDを指定)
gog chat messages send spaces/AAAA9qhlGLw \
--text "詳細: Chat Delete機能はGoで実装しました" \
--thread spaces/AAAA9qhlGLw/threads/<threadId> \
--account [email protected]
Google Chat APIがサポートするテキスト書式:
| 書式 | 記法 | 結果 |
|---|---|---|
| 太字 | *テキスト* | テキスト |
| 斜体 | _テキスト_ | テキスト |
| 取り消し線 | ~テキスト~ | |
| コード | `テキスト` | テキスト |
Drive画像のリンク共有
Google Chat APIはメッセージに画像を直接添付できない(APIの制限)。画像を共有するにはDriveにアップロードしてリンクを送る。
# 1. ローカル画像をDriveにアップロード
gog drive upload C:\Users\numbe\Pictures\screenshot.png \
--parent <folderId> \
--account [email protected]
# 2. ChatスレッドにDriveリンクを投稿
gog chat messages send spaces/AAAA9qhlGLw \
--text "スクリーンショット: https://drive.google.com/file/d/<fileId>/view" \
--thread spaces/AAAA9qhlGLw/threads/<threadId> \
--account [email protected]
4. keyringバックエンド問題の解決
症状
gogcliのコマンド実行時に以下のエラーが出た。
token source: get token for [email protected]: read token: open C:\Users\...\keyring\token:default:[email protected]: The filename, directory name, or volume label syntax is incorrect.
原因
OAuthトークンはWindows Credential Manager(auto バックエンド)に保存されていた。しかし config.json の keyring_backend がいつの間にか file に変わっていた。
file バックエンドはファイル名にコロン(:)を使う設計になっている。Windowsではコロンがファイルパスに使えないため、パスが不正になりトークンを読み込めなかった。
解決
keyringバックエンドを auto に戻すだけで直った。
# バックエンドをautoに戻す
gog auth keyring auto
# 確認
gog auth keyring
# → keyring_backend: auto, source: config
# アカウントが見えるか確認
gog auth list
トークンはWindows Credential Managerに保存されているため、バイナリをビルドし直しても消えない。バックエンドの設定さえ正しければトークンはそのまま使える。
教訓
- gogcliの
config.jsonを手動で触った場合、keyring_backendの値が変わっていないか確認する - Windowsでは
fileバックエンドは避けたほうがよい(コロン問題) autoにしておけばOS標準のCredential Managerが使われる
5. Drive検索の制限事項
gogcliの drive search と drive ls --query は動作が違う。
drive search はフルテキスト検索のみ
# NG: mimeTypeフィルタが効かない
gog drive search "mimeType='image/png'" --account [email protected]
# OK: ファイル名でのフルテキスト検索は動く
gog drive search "NAAIM" --account [email protected]
drive search は内部で files.list の q パラメータに fullText contains '...' を設定している。そのため mimeType や name contains のようなDrive APIクエリ構文は使えない。
drive ls --query ならDrive APIクエリがそのまま使える
# 画像ファイルを検索
gog drive ls --query "mimeType='image/png'" --max 10 --account [email protected]
# 特定フォルダ内のファイル
gog drive ls --query "'<folderId>' in parents" --max 20 --account [email protected]
# 名前で部分一致検索
gog drive ls --query "name contains 'レポート'" --max 10 --account [email protected]
画像を探す場合は drive ls --query を使う。drive search はファイル名がわかっているときだけ使えばよい。
6. GAS→Python移行手順の公開記事
gogcliの実用テストと並行して、Google Apps Script + SheetsをPython + CSVに移行する記事を作成・公開した。
記事の概要
- gogcliでSheetsのデータと数式を取得
- claspでGASのソースコードを取得
- Claude Codeに両方を読ませてPython + CSVに変換
レビューと校正
記事はCodexによるレビューとhonda-sakubun(本多式作文)による校正を経て公開した。技術記事に特有の冗長な説明を削り、手順を結論から書く構成に修正した。
まとめ
今回やったことの一覧:
| 作業 | 内容 |
|---|---|
| Chat Delete実装 | GoでCLIコマンドを追加し、テスト送信メッセージの削除をCLIから実行できるようにした |
| フォーク管理 | origin→upstreamリネーム、feat/chat-deleteブランチ、GitHubプッシュ、LOCAL_OPS.md作成 |
| API実用テスト | メッセージ取得・削除・スレッド送信・Drive画像リンク共有を一通り確認 |
| keyring問題 | Windows Credential Manager → fileバックエンド設定ミスを gog auth keyring auto で修正 |
| Drive検索 | drive search(フルテキストのみ)と drive ls --query(Drive APIクエリ対応)の違いを把握 |
| GAS→Python記事 | gogcliとclaspを使った移行手順を公開(Codexレビュー・honda-sakubun校正済み) |
gogcliは本家の更新が活発で、今後Chat Delete機能が本家に入る可能性もある。そのときは upstream/main にマージして自分のブランチを削除すればよい。フォーク管理のルールを LOCAL_OPS.md に書いておいたので、追従作業で迷うことはないはず。