Files
log/claude.md
2026-01-08 17:30:51 +09:00

382 lines
8.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ailog
## 概要
atprotoベースの静的ブログジェネレーター。markdownファイルをatproto recordとして保存し、それを元に静的サイトを生成する。
## Collection Schema
### ai.syui.log.post (ブログ記事)
```json
{
"lexicon": 1,
"id": "ai.syui.log.post",
"defs": {
"main": {
"type": "record",
"description": "Record containing a blog post.",
"key": "tid",
"record": {
"type": "object",
"required": ["title", "content", "createdAt"],
"properties": {
"title": {
"type": "string",
"maxLength": 3000,
"maxGraphemes": 300,
"description": "The title of the post."
},
"content": {
"type": "string",
"maxLength": 1000000,
"maxGraphemes": 100000,
"description": "The content of the post."
},
"createdAt": {
"type": "string",
"format": "datetime",
"description": "Client-declared timestamp when this post was originally created."
}
}
}
}
}
}
```
### ai.syui.log.comment (コメント)
```json
{
"lexicon": 1,
"id": "ai.syui.log.comment",
"defs": {
"main": {
"type": "record",
"description": "Record containing a comment.",
"key": "tid",
"record": {
"type": "object",
"required": ["content", "createdAt", "post"],
"properties": {
"content": {
"type": "string",
"maxLength": 100000,
"maxGraphemes": 10000,
"description": "The content of the comment."
},
"createdAt": {
"type": "string",
"format": "datetime",
"description": "Client-declared timestamp when this comment was originally created."
},
"parent": {
"type": "ref",
"ref": "com.atproto.repo.strongRef"
},
"post": {
"type": "ref",
"ref": "com.atproto.repo.strongRef"
}
}
}
}
}
}
```
## CLIコマンド仕様
### login - ログイン
```bash
ailog login ${handle} -p ${password} -s ${pds}
```
- handleからDID, PDSを解決
- 認証情報を`~/.config/syui/ai/log/config.json`に保存
### post - 記事をatprotoに投稿
```bash
ailog post
```
- `./content/post/*.md`を読み込む
- frontmatterからtitle, dateなどを抽出
- markdown本文をcontentに設定
- `ai.syui.log.post`としてputRecord
- 既存recordがあれば更新、なければ新規作成
### build - 静的サイト生成
```bash
ailog build
```
- atprotoから`ai.syui.log.post`のrecordを取得
- markdownをHTMLに変換
- 静的ファイルとして`./public`に出力
## URL構造
### 記事一覧
```
localhost/at://did:plc:ragtjsm2j2vknwkz3zp4oxrd/ai.syui.log.post/
```
- atprotoから全recordを取得
- 一覧表示
### 個別記事
```
localhost/.../3mbnbdt4bas2a
```
- atproto URIからrecordを取得
- markdownをレンダリングして表示
## データフロー
### 記事投稿
```
./content/post/*.md
↓ (frontmatter + markdown解析)
ailog post
↓ (putRecord)
atproto PDS (ai.syui.log.post)
```
### 静的サイト生成
```
atproto PDS (ai.syui.log.post)
↓ (listRecords)
ailog build
↓ (markdown → HTML)
./public/*.html
```
## at browser統合
- atproto URIでの記事アクセス
- handle解決 → DID → PDS URLの取得
- NetworkConfig (pdsApi, bskyApi, plcApi) の割り当て
```rust
match pds {
"bsky.social" | "bsky.app" => NetworkConfig {
pds_api: format!("https://{}", pds),
plc_api: "https://plc.directory".to_string(),
bsky_api: "https://public.api.bsky.app".to_string(),
web_url: "https://bsky.app".to_string(),
},
"syu.is" => NetworkConfig {
pds_api: "https://syu.is".to_string(),
plc_api: "https://plc.syu.is".to_string(),
bsky_api: "https://bsky.syu.is".to_string(),
web_url: "https://web.syu.is".to_string(),
},
_ => NetworkConfig {
pds_api: format!("https://{}", pds),
plc_api: "https://plc.directory".to_string(),
bsky_api: "https://public.api.bsky.app".to_string(),
web_url: "https://bsky.app".to_string(),
}
}
```
## 参考実装
- `./repos/log` - 既存のailog実装 (Rust)
- `./repos/frontpage` - frontpage (fyi.unravel.frontpage)
- `./repos/pfrazee.com` - Paul FrazeeのLeaflet実装 (TypeScript)
## Paul Frazeeの仕組み
pfrazee.comは以下の流れでLeafletをblogに統合
1. **lexicon schema取得**
```bash
lex install pub.leaflet.document
lex build --out ./util
```
2. **データ取得**
```typescript
// handle → DID → PDS
const did = await resolver.handle.resolve('pfrazee.com')
const pds = await resolver.did.resolveAtprotoData(did).pds
// listRecords
const result = await client.list(leaflet.document, {
repo: did,
limit: 50
})
```
3. **画像取得**
```typescript
for (const blobRef of enumBlobRefs(leaflet.value)) {
const blobRes = await client.getBlob(did, blobRef.ref)
await fsp.writeFile(imagePath, blobRes.payload.body)
}
```
4. **静的サイト生成** (Next.js)
- JSONからHTMLレンダリング
- 型安全なblock rendering
## 既存のai.syui.log形式
現在のchat形式
```json
{
"uri": "at://did:plc:6qyecktefllvenje24fcxnie/ai.syui.log/2025-06-14-blog",
"value": {
"url": "https://syui.ai/posts/2025-06-14-blog",
"post": {
"url": "https://syui.ai/posts/2025-06-14-blog",
"date": "",
"slug": "",
"tags": [],
"title": "syui.ai",
"language": "ja"
},
"text": "test",
"type": "comment",
"$type": "ai.syui.log",
"author": {
"did": "did:plc:6qyecktefllvenje24fcxnie",
"avatar": "https://...",
"handle": "ai.syui.ai",
"displayName": "ai"
},
"createdAt": "2025-06-17T06:24:37.386Z"
}
}
```
## 設定ファイル
### ~/.config/syui/ai/log/config.json
```json
{
"pds": "syu.is",
"handle": "ai.syui.ai",
"did": "did:plc:6qyecktefllvenje24fcxnie",
"access_jwt": "...",
"refresh_jwt": "..."
}
```
### ~/.config/syui/ai/log/mapping.json
ファイル名とatproto recordの紐付け自動生成
```json
{
"2026-01-08-test.md": {
"rkey": "3mbnbdt4bas2a",
"uri": "at://did:plc:xxx/ai.syui.log.post/3mbnbdt4bas2a",
"cid": "bafyrei..."
}
}
```
**動作:**
- すべてのAPI呼び出し前に自動でrefreshSessionを実行してJWTトークンを更新
- `ailog post` - 初回投稿時にTID形式のrkeyが自動生成され、mappingに保存
- `ailog post` - 2回目以降は既存rkeyで更新putRecord
- `ailog delete` - 全削除時にmappingもクリア
## ディレクトリ構造
```
ailog/
├── content/
│ └── post/
│ ├── 2025-01-08-example.md
│ └── ...
├── public/
│ ├── index.html
│ ├── posts/
│ │ └── 2025-01-08-example.html
│ └── at/
│ └── ...
├── lexicons/
│ └── ai/
│ └── syui/
│ └── log/
│ ├── post.json
│ └── comment.json
└── templates/
├── index.html
├── post.html
└── layout.html
```
## 開発優先順位
1. CLIコマンド実装 ✅
- [x] collection schema定義
- [x] `ailog login` - handle → DID解決 + JWT保存
- [x] `ailog post` - ./content/post/*.md → putRecord
- [x] `ailog build` - listRecords → 静的HTML生成
2. at browser統合 (進行中)
- [x] React/TypeScript環境セットアップ
- [x] atproto client library (repos/log/pdsベース)
- [ ] at browser components
- [ ] 静的サイトへの統合
- [ ] ai.syui.log.post 表示スタイル
3. スタイリング
- [ ] Tailwind CSS統合
- [ ] repos/log風デザイン
## 実装済み
### Rust CLI (src/)
- `src/main.rs` - CLIエントリーポイント
- `src/config.rs` - ~/.config/syui/ai/log/config.json管理
- `src/login.rs` - atproto認証 (describeRepo + createSession)
- `src/refresh.rs` - セッションリフレッシュ (refreshSession)
- `src/post.rs` - markdown投稿 (createRecord/putRecord)
- `src/build.rs` - 静的サイト生成 (listRecords + markdown→HTML)
- `src/delete.rs` - record削除 (deleteRecord)
### at browser (browser/)
- `browser/package.json` - React + TypeScript + Tailwind
- 実装予定: repos/log/pdsの実装をベースに作成
## 使用方法
```bash
# ログイン
ailog l ai.syui.ai -p PASSWORD -s syu.is
# 記事投稿(初回: 新規作成、2回目以降: 更新)
ailog p
# サイト生成
ailog b
# 全削除
ailog d
```
**エイリアス:**
- `l` = `login`
- `p` = `post`
- `b` = `build`
- `d` = `delete`