fix
This commit is contained in:
1
browser/dist/assets/index-CvFXbZtL.css
vendored
1
browser/dist/assets/index-CvFXbZtL.css
vendored
@@ -1 +0,0 @@
|
||||
.container{max-width:800px;margin:0 auto;padding:2rem}h1{font-size:2rem;margin-bottom:1.5rem;color:#333}.input-section{margin-bottom:2rem;display:flex;gap:.5rem}.at-uri-input{flex:1;padding:.75rem;font-size:1rem;border:2px solid #ddd;border-radius:4px;font-family:monospace}.at-uri-input:focus{outline:none;border-color:#06c}.input-section button{padding:.75rem 2rem;font-size:1rem;background:#06c;color:#fff;border:none;border-radius:4px;cursor:pointer;font-weight:500}.input-section button:hover{background:#0052a3}.info-section{background:#fff;padding:1.5rem;border-radius:8px;margin-bottom:2rem;box-shadow:0 2px 4px #0000001a}.info-section h2{font-size:1.5rem;margin-bottom:1rem;color:#333}.info-section ul{list-style-position:inside;color:#666}.info-section li{margin-bottom:.5rem}.back-link{display:inline-block;color:#06c;text-decoration:none;font-weight:500}.back-link:hover{text-decoration:underline}.record-view{background:#fff;padding:2rem;border-radius:8px;margin-bottom:2rem;box-shadow:0 2px 4px #0000001a}.record-view h2{font-size:2rem;margin-bottom:1rem;color:#333}.record-meta{margin-bottom:1.5rem;padding-bottom:1rem;border-bottom:1px solid #eee}.record-meta p{margin:.5rem 0;color:#666;font-size:.9rem;font-family:monospace}.record-content{line-height:1.8;color:#333}.record-content pre{white-space:pre-wrap;word-wrap:break-word;font-family:inherit;margin:0}*{margin:0;padding:0;box-sizing:border-box}body{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;background:#f5f5f5}code{font-family:source-code-pro,Menlo,Monaco,Consolas,Courier New,monospace}
|
||||
File diff suppressed because one or more lines are too long
1
browser/dist/assets/index-t2ajyYjt.css
vendored
Normal file
1
browser/dist/assets/index-t2ajyYjt.css
vendored
Normal file
@@ -0,0 +1 @@
|
||||
.container{max-width:800px;margin:0 auto;padding:2rem}h1{font-size:2rem;margin-bottom:1.5rem;color:#333}.input-section{margin-bottom:2rem;display:flex;gap:.5rem}.at-uri-input{flex:1;padding:.75rem;font-size:1rem;border:2px solid #ddd;border-radius:4px;font-family:monospace}.at-uri-input:focus{outline:none;border-color:#06c}.input-section button{padding:.75rem 2rem;font-size:1rem;background:#06c;color:#fff;border:none;border-radius:4px;cursor:pointer;font-weight:500}.input-section button:hover{background:#0052a3}.info-section{background:#fff;padding:1.5rem;border-radius:8px;margin-bottom:2rem;box-shadow:0 2px 4px #0000001a}.info-section h2{font-size:1.5rem;margin-bottom:1rem;color:#333}.info-section ul{list-style-position:inside;color:#666}.info-section li{margin-bottom:.5rem}.back-link{display:inline-block;color:#06c;text-decoration:none;font-weight:500}.back-link:hover{text-decoration:underline}.record-view{background:#fff;padding:2rem;border-radius:8px;margin-bottom:2rem;box-shadow:0 2px 4px #0000001a}.record-view h2{font-size:2rem;margin-bottom:1rem;color:#333}.record-meta{margin-bottom:1.5rem;padding-bottom:1rem;border-bottom:1px solid #eee}.record-meta p{margin:.5rem 0;color:#666;font-size:.9rem;font-family:monospace}.record-content{line-height:1.8;color:#333}.record-content pre{white-space:pre-wrap;word-wrap:break-word;font-family:inherit;margin:0}.error-section{background:#fee;padding:1rem;border-radius:4px;margin-bottom:1rem;color:#c33}.records-list{background:#fff;padding:2rem;border-radius:8px;margin-bottom:2rem;box-shadow:0 2px 4px #0000001a}.records-list h2{font-size:1.5rem;margin-bottom:1rem;color:#333}.records-list ul{list-style:none;padding:0;margin:0}.records-list li{border-bottom:1px solid #eee}.records-list li:last-child{border-bottom:none}.record-link{display:flex;justify-content:space-between;align-items:center;width:100%;padding:1rem;background:none;border:none;cursor:pointer;text-align:left;transition:background .2s}.record-link:hover{background:#f5f5f5}.record-title{font-size:1.1rem;color:#06c;font-weight:500}.record-date{color:#666;font-size:.9rem}.back-button{padding:.5rem 1rem;margin-bottom:1rem;background:#f5f5f5;border:1px solid #ddd;border-radius:4px;cursor:pointer;font-size:.9rem;color:#666}.back-button:hover{background:#eee}.input-section button:disabled{background:#ccc;cursor:not-allowed}*{margin:0;padding:0;box-sizing:border-box}body{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;background:#f5f5f5}code{font-family:source-code-pro,Menlo,Monaco,Consolas,Courier New,monospace}
|
||||
4
browser/dist/index.html
vendored
4
browser/dist/index.html
vendored
@@ -4,8 +4,8 @@
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>AT Browser</title>
|
||||
<script type="module" crossorigin src="/at/assets/index-DrFpc8Xj.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/at/assets/index-CvFXbZtL.css">
|
||||
<script type="module" crossorigin src="/at/assets/index-CyrVFHrY.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/at/assets/index-t2ajyYjt.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
|
||||
381
claude.md
381
claude.md
@@ -1,381 +0,0 @@
|
||||
# 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`
|
||||
Reference in New Issue
Block a user