Yu Takahashi

AIdocker

AIエージェントを安全に動かすサンドボックス環境の作成

Claude Code の Auto Mode や GitHub Copilot CLI の Autopilot など、AIエージェントを自律的に動かす機能があります。 これらは非常に便利な反面、ホスト環境で直接動かすのは少し不安です。依存パッケージが汚染されたり、意図しないファイルを書き換えられたりするリスクがあります。 そこで今回は、エージェントをコンテナ内に閉じ込めつつ、ホストのプロジェクトディレクトリをシームレスに扱えるサンドボックス環境を作成しました。 https://github.com/yutakahashi114/sandbox -------------------------------------------------------------------------------- 概要 このツールは1つのシェルスクリプト sandbox を実行するだけで、Docker コンテナ上の開発環境に入ることができます。 $ sandbox # 現在のディレクトリで新しいセッションを開く $ sandbox -- <cm
Yu Takahashi
Yu Takahashi
3 min read
VSCode

VS Codeでファイル名と行数をコピーできる拡張機能を作成した

最近、GitHub Copilot や Roo Code など、AI を使ってコードを書くことが増えてきました。 プロンプトでなるべく具体的な指示をすることで精度が向上します。 例えば、自分は以下のように書くことが多いです。 「ファイルAのn行目の関数Bを(使用/修正/参考に)してください」 しかし、このプロンプト文を書くのが地味に面倒でした。自分は開発に Visual Studio Code (VS Code) を使用していますが、 ファイル名をコピペ→行数を入力→関数名等をコピペ のように書いていました。 そこで、ファイル名と行数をまとめてコピーできる拡張機能を作成しました。 作成した拡張機能 * VS Code Marketplace https://marketplace.visualstudio.com/items?itemName=yutakahashi114.copy-with-file-path * GitHub https://github.com/yutakahashi114/copy-with-file-path
Yu Takahashi
Yu Takahashi
1 min read
GitHub ActionsGitHub Apps

GitHub Actions で外部の組織のプライベートリポジトリにPRを出す

はじめに organization Aのプライベートリポジトリのコードに変更があった時、organization BのプライベートリポジトリにGitHub ActionsでPRを出したい、というケースがありました。 同じ組織の別リポジトリへPRを出す方法は、調べるといくつか記事が出てきますが、別の組織の場合は設定を変える必要があります。 少しハマったので、記録として残しておきます。 やりたいこと org-a の repo-a から org-b の repo-b にPRを出す。 方法 以下の記事を参考にしました。 GitHub Apps / GitHub Actionsを使って別のリポジトリにファイルをコピーするPRを作成するZennHirotaka Miyagi [https://zenn.dev/mh4gf/articles/copy-file-to-another-repository] この記事では同じ組織の別リポジトリへのPRの場合なので、別の組織の場合に変更する部分を説明します。 GitHub Apps GitHub Apps は org-b の組織に作成、インス
Yu Takahashi
Yu Takahashi
2 min read
Go

Goのサーバーでcontext canceledをハンドリングする

はじめに Goでecho [https://github.com/labstack/echo]を使って以下のようなサーバーを作っていました。 var db *sql.DB func main() { e := echo.New() e.POST("/", func(c echo.Context) error { ctx := c.Request().Context() // 自身の管理するDBに保存する db.ExecContext(ctx, "INSERT INTO ...") // 別のサーバーで管理するDBに保存する req, err := http.NewRequestWithContext( ctx, http.MethodPost, "http://localhost:8081/", nil, ) if err != nil { return err } res, err := http.DefaultClient.Do(req) ... return c.NoContent(http
Yu Takahashi
Yu Takahashi
2 min read

Goの関数内で引数の値を書き換えた時の影響

はじめに 関数の引数の値を書き換えた時、呼び出し元で渡した変数の値にも影響がある場合があります。どのような場合に影響があるのか​​、定期的に忘れるため書き残しておきました。 調査 以下の構造体で試してみます。 type TestStruct struct { Value User Pointer *User ValueSlice ValueUsers PointerSlice PointerUsers } type User struct { ID int } type ValueUsers []User type PointerUsers []*User 関数の引数に渡したとき、各フィールドのポイントインタがどうなるかを確認します。 package main import ( "fmt" "os" "strings" "github.com/olekukonko/tablewriter" ) func main() { a := TestStruct{ Value: User{ ID: 1, },
Yu Takahashi
Yu Takahashi
5 min read
Go

Goで外部通信の中身を確認する

使用しているライブラリの外部通信の中身(リクエストのヘッダやレスポンスのステータス等)をデバッグのために出力したくなったのでまとめました。 方法 以下のように外部のサーバーにリクエストするようなコードがあったとします。 package main import ( "context" "fmt" "net/http" ) func main() { if err := run(); err != nil { panic(err) } } var c = &http.Client{} func run() error { ctx := context.Background() req, err := http.NewRequestWithContext( ctx, http.MethodGet, "http://localhost:8080", nil, ) if err != nil { return err } res, err := c.Do(req) if err != nil { return err } fmt
Yu Takahashi
Yu Takahashi
3 min read
Go

Goで構造体をcomparableとして使う場合の注意点

Go1.18から導入された型パラメータ comparable は、 == や != で比較可能な型のみを受け入れます。 mapのキーにジェネリックな型を指定するような関数でよく使うと思います。 func ToMap[T comparable](ss []T) map[T]struct{} { m := make(map[T]struct{}, len(ss)) for _, s := range ss { m[s] = struct{}{} } return m } int や string などの組み込み型はもちろん、構造体も comparable を満たします。 type User struct { ID int Name string } func main() { us := []User{ { ID: 1, Name: "1", }, { ID: 2, Name: "2", }, } m := ToMap(us) _, ok := m[User{ID: 1, Name: "1"}] fm
Yu Takahashi
Yu Takahashi
1 min read
Go

Goのキャッシュ実装をジェネリクスで共通化する

はじめに GoでRedisを使ったキャッシュを実装する際、同じような処理を何度も書くことになりそうだったので共通化しました。 実装 Redisへリクエストする処理をinterfaceで定義しておきます。 type Client interface { Get(context.Context, string) ([]byte, bool, error) Set(context.Context, string, []byte, time.Duration) error } このinterfaceを満たすclientを実装します。Redisへの接続には github.com/go-redis/redis [https://pkg.go.dev/github.com/go-redis/redis/v8@v8.11.5] を使いました。 type client struct { c *redis.Client } func NewClient(addr, pass string) cache.Client { c := redis.NewClient( &redis.Op
Yu Takahashi
Yu Takahashi
2 min read
Go

Goのcontextのkeyについて

はじめに Goの標準パッケージの context.Context は context.WithValue 関数を使って任意の値を格納することができます。 context.WithValue には以下のようなコメントが書かれています。 // WithValue returns a copy of parent in which the value associated with key is // val. // // Use context Values only for request-scoped data that transits processes and // APIs, not for passing optional parameters to functions. // // The provided key must be comparable and should not be of type // string or any other built-in type to avoid collisions between // packages using c
Yu Takahashi
Yu Takahashi
6 min read
Go

Goでsliceの一部を抽出する時の注意点

sliceの構造 Goのsliceは 配列へのポインタ 長さ 容量 を持った構造体として定義されています。 go/slice.go at go1.18 · golang/goThe Go programming language. Contribute to golang/go development by creating an account on GitHub.GitHubgolang [https://github.com/golang/go/blob/go1.18/src/runtime/slice.go#L15-L19]type slice struct { array unsafe.Pointer len int cap int } sliceの構造については以下の記事が分かりやすかったです。 実装して理解するスライス #golang - Qiitaはじめに この記事はGoアドベントカレンダーの1日目の記事です。 スライスの実態 runtimeのコードをみるとGoのスライスは以下のように定義されています。 type slice struct { arr
Yu Takahashi
Yu Takahashi
4 min read
Go

Goのinterfaceのnilについて

interfaceのnilチェックをしているのにメソッド呼び出し時にpanicが起きることがあり、その時に調べたことのメモです。 該当コードを簡略化して書くと以下のような感じです。 package main import "fmt" type Message interface { Str() string } var _ Message = &Text{} type Text struct { text string } func (t *Text) Str() string { return t.text } func NewText(str string) *Text { if str == "" { return nil } return &Text{ text: str, } } NewText() は引数が空文字の場合にnilを返します。 これに対して、以下のような Print() 関数を用意して実行すると、 func Print(m Message) { if m != nil { fmt.Println(m.Str
Yu Takahashi
Yu Takahashi
1 min read

Amazon Cognito でメールアドレス変更する際の注意点

Amazon Cognito のメールアドレス変更には以下のような問題があります。 Cognitoでメールアドレス編集するとログインできなくなる問題Zennハトすけ [https://zenn.dev/dove/articles/78ecf08b51ee0c]> * 新しいメールアドレスを申請して、メールで検証をする前にその新しいメールでログインできてしまう * 逆に検証が成功していないのに古いメールアドレスでログインできない * つまり間違ったメールアドレスをリクエストするとその時点で詰む(ユーザーロックというらしい) これを回避する方法は上の記事やissue [https://github.com/aws-amplify/amplify-js/issues/987] にいくつか書かれています。 以下では、個人的にベターと思う方法を書きました。 今回Golangのサーバーで実装していますが、同じロジックでlambdaでの実装もできると思います。 基本的な方針は以下を参考にしました。 Change email with AWS Cognito and Amplify - Jo
Yu Takahashi
Yu Takahashi
3 min read