diff --git a/.env.example b/.env.example
deleted file mode 100644
index 647e7fa..0000000
--- a/.env.example
+++ /dev/null
@@ -1,3 +0,0 @@
-# LMS Translation API
-TRANSLATE_URL=http://127.0.0.1:1234/v1
-TRANSLATE_MODEL=plamo-2-translate
diff --git a/.github/workflows/cf-pages.yml b/.github/workflows/cf-pages.yml
deleted file mode 100644
index 80d3d23..0000000
--- a/.github/workflows/cf-pages.yml
+++ /dev/null
@@ -1,36 +0,0 @@
-name: Deploy to Cloudflare Pages
-
-on:
- push:
- branches:
- - main
- workflow_dispatch:
-
-jobs:
- deploy:
- runs-on: ubuntu-latest
- permissions:
- contents: read
- deployments: write
-
- steps:
- - name: Checkout
- uses: actions/checkout@v4
-
- - name: Setup Node.js
- uses: actions/setup-node@v4
-
- - name: Install dependencies
- run: npm install
-
- - name: Build content from ATProto
- run: npm run build
-
- - name: Deploy to Cloudflare Pages
- uses: cloudflare/pages-action@v1
- with:
- apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
- accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
- projectName: ${{ secrets.CLOUDFLARE_PROJECT_NAME }}
- directory: dist
- gitHubToken: ${{ secrets.GITHUB_TOKEN }}
diff --git a/Cargo.toml b/Cargo.toml
deleted file mode 100644
index bc37255..0000000
--- a/Cargo.toml
+++ /dev/null
@@ -1,24 +0,0 @@
-[package]
-name = "ailog"
-version = "0.0.1"
-edition = "2021"
-description = "ATProto blog CLI"
-authors = ["syui"]
-homepage = "https://syui.ai"
-repository = "https://git.syui.ai/ai/log"
-
-[[bin]]
-name = "ailog"
-path = "src/main.rs"
-
-[dependencies]
-clap = { version = "4.5", features = ["derive"] }
-serde = { version = "1.0", features = ["derive"] }
-serde_json = "1.0"
-reqwest = { version = "0.12", features = ["json", "rustls-tls"], default-features = false }
-tokio = { version = "1", features = ["rt-multi-thread", "macros"] }
-anyhow = "1.0"
-dirs = "5.0"
-chrono = { version = "0.4", features = ["serde"] }
-rand = "0.8"
-dotenvy = "0.15"
diff --git a/index.html b/index.html
index e172358..f4f46e1 100644
--- a/index.html
+++ b/index.html
@@ -3,7 +3,7 @@
- syui.ai
+ syui.github.io
diff --git a/lexicons/ai.syui.log.post.json b/lexicons/ai.syui.log.post.json
deleted file mode 100644
index ad2f85b..0000000
--- a/lexicons/ai.syui.log.post.json
+++ /dev/null
@@ -1,68 +0,0 @@
-{
- "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 (markdown)."
- },
- "createdAt": {
- "type": "string",
- "format": "datetime",
- "description": "Client-declared timestamp when this post was originally created."
- },
- "lang": {
- "type": "string",
- "maxLength": 10,
- "description": "Language code of the original content (e.g., 'ja', 'en')."
- },
- "translations": {
- "type": "ref",
- "ref": "#translationMap",
- "description": "Translations of the post in other languages."
- }
- }
- }
- },
- "translationMap": {
- "type": "object",
- "description": "Map of language codes to translations.",
- "properties": {
- "en": { "type": "ref", "ref": "#translation" },
- "ja": { "type": "ref", "ref": "#translation" }
- }
- },
- "translation": {
- "type": "object",
- "description": "A translation of a post.",
- "properties": {
- "title": {
- "type": "string",
- "maxLength": 3000,
- "maxGraphemes": 300
- },
- "content": {
- "type": "string",
- "maxLength": 1000000,
- "maxGraphemes": 100000
- }
- }
- }
- }
-}
diff --git a/public/config.json b/public/config.json
index a5358af..44668c7 100644
--- a/public/config.json
+++ b/public/config.json
@@ -1,8 +1,8 @@
{
- "title": "syui.ai",
- "handle": "syui.syui.ai",
+ "title": "syui.github.io",
+ "handle": "syui.ai",
"collection": "ai.syui.log.post",
- "network": "syu.is",
+ "network": "bsky.social",
"color": "#EF454A",
- "siteUrl": "https://syui.ai"
+ "siteUrl": "https://syui.github.io"
}
diff --git a/src/commands/auth.rs b/src/commands/auth.rs
deleted file mode 100644
index 6a93c82..0000000
--- a/src/commands/auth.rs
+++ /dev/null
@@ -1,97 +0,0 @@
-use anyhow::{Context, Result};
-use serde::{Deserialize, Serialize};
-
-use super::token::{self, Session};
-use crate::lexicons::{self, com_atproto_server};
-
-#[derive(Debug, Serialize)]
-struct CreateSessionRequest {
- identifier: String,
- password: String,
-}
-
-#[derive(Debug, Deserialize)]
-#[serde(rename_all = "camelCase")]
-struct CreateSessionResponse {
- did: String,
- handle: String,
- access_jwt: String,
- refresh_jwt: String,
-}
-
-/// Login to ATProto PDS
-pub async fn login(handle: &str, password: &str, pds: &str) -> Result<()> {
- let client = reqwest::Client::new();
- let url = lexicons::url(pds, &com_atproto_server::CREATE_SESSION);
-
- let req = CreateSessionRequest {
- identifier: handle.to_string(),
- password: password.to_string(),
- };
-
- println!("Logging in to {} as {}...", pds, handle);
-
- let res = client
- .post(&url)
- .json(&req)
- .send()
- .await
- .context("Failed to send login request")?;
-
- if !res.status().is_success() {
- let status = res.status();
- let body = res.text().await.unwrap_or_default();
- anyhow::bail!("Login failed: {} - {}", status, body);
- }
-
- let session_res: CreateSessionResponse = res.json().await?;
-
- let session = Session {
- did: session_res.did,
- handle: session_res.handle,
- access_jwt: session_res.access_jwt,
- refresh_jwt: session_res.refresh_jwt,
- pds: Some(pds.to_string()),
- };
-
- token::save_session(&session)?;
- println!("Logged in as {} ({})", session.handle, session.did);
-
- Ok(())
-}
-
-/// Refresh access token
-pub async fn refresh_session() -> Result {
- let session = token::load_session()?;
- let pds = session.pds.as_deref().unwrap_or("bsky.social");
-
- let client = reqwest::Client::new();
- let url = lexicons::url(pds, &com_atproto_server::REFRESH_SESSION);
-
- let res = client
- .post(&url)
- .header("Authorization", format!("Bearer {}", session.refresh_jwt))
- .send()
- .await
- .context("Failed to refresh session")?;
-
- if !res.status().is_success() {
- let status = res.status();
- let body = res.text().await.unwrap_or_default();
- anyhow::bail!("Refresh failed: {} - {}. Try logging in again.", status, body);
- }
-
- let new_session: CreateSessionResponse = res.json().await?;
-
- let session = Session {
- did: new_session.did,
- handle: new_session.handle,
- access_jwt: new_session.access_jwt,
- refresh_jwt: new_session.refresh_jwt,
- pds: Some(pds.to_string()),
- };
-
- token::save_session(&session)?;
-
- Ok(session)
-}
diff --git a/src/commands/did.rs b/src/commands/did.rs
deleted file mode 100644
index a7ee961..0000000
--- a/src/commands/did.rs
+++ /dev/null
@@ -1,34 +0,0 @@
-use anyhow::{Context, Result};
-use serde::Deserialize;
-
-use crate::lexicons::{self, com_atproto_identity};
-
-#[derive(Debug, Deserialize)]
-struct ResolveHandleResponse {
- did: String,
-}
-
-/// Resolve handle to DID
-pub async fn resolve(handle: &str, server: &str) -> Result<()> {
- let client = reqwest::Client::new();
- let url = format!(
- "{}?handle={}",
- lexicons::url(server, &com_atproto_identity::RESOLVE_HANDLE),
- handle
- );
-
- let res = client.get(&url).send().await?;
-
- if !res.status().is_success() {
- let status = res.status();
- let body = res.text().await.unwrap_or_default();
- anyhow::bail!("Failed to resolve handle: {} - {}", status, body);
- }
-
- let result: ResolveHandleResponse = res.json().await
- .context("Failed to parse response")?;
-
- println!("{}", result.did);
-
- Ok(())
-}
diff --git a/src/commands/gen.rs b/src/commands/gen.rs
deleted file mode 100644
index 6f59d23..0000000
--- a/src/commands/gen.rs
+++ /dev/null
@@ -1,265 +0,0 @@
-use anyhow::{Context, Result};
-use serde::Deserialize;
-use std::collections::BTreeMap;
-use std::fs;
-use std::path::Path;
-
-#[derive(Debug, Deserialize)]
-struct Lexicon {
- id: String,
- defs: BTreeMap,
-}
-
-#[derive(Debug, Deserialize)]
-struct LexiconDef {
- #[serde(rename = "type")]
- def_type: Option,
-}
-
-struct EndpointInfo {
- nsid: String,
- method: String, // GET or POST
-}
-
-/// Generate lexicon code from ATProto lexicon JSON files
-pub fn generate(input: &str, output: &str) -> Result<()> {
- let input_path = Path::new(input);
-
- if !input_path.exists() {
- anyhow::bail!("Input directory does not exist: {}", input);
- }
-
- println!("Scanning lexicons from: {}", input);
-
- // Collect all endpoints grouped by namespace
- let mut namespaces: BTreeMap> = BTreeMap::new();
-
- // Scan com/atproto directory
- let atproto_path = input_path.join("com/atproto");
- if atproto_path.exists() {
- scan_namespace(&atproto_path, "com.atproto", &mut namespaces)?;
- }
-
- // Scan app/bsky directory
- let bsky_path = input_path.join("app/bsky");
- if bsky_path.exists() {
- scan_namespace(&bsky_path, "app.bsky", &mut namespaces)?;
- }
-
- // Generate Rust code
- let rust_code = generate_rust_code(&namespaces);
- let rust_output_path = Path::new(output).join("mod.rs");
- fs::create_dir_all(output)?;
- fs::write(&rust_output_path, &rust_code)?;
- println!("Generated Rust: {}", rust_output_path.display());
-
- // Generate TypeScript code
- let ts_output = output.replace("src/lexicons", "src/web/lexicons");
- let ts_code = generate_typescript_code(&namespaces);
- let ts_output_path = Path::new(&ts_output).join("index.ts");
- fs::create_dir_all(&ts_output)?;
- fs::write(&ts_output_path, &ts_code)?;
- println!("Generated TypeScript: {}", ts_output_path.display());
-
- println!("Total namespaces: {}", namespaces.len());
- let total_endpoints: usize = namespaces.values().map(|v| v.len()).sum();
- println!("Total endpoints: {}", total_endpoints);
-
- Ok(())
-}
-
-fn scan_namespace(
- base_path: &Path,
- prefix: &str,
- namespaces: &mut BTreeMap>,
-) -> Result<()> {
- for entry in fs::read_dir(base_path)? {
- let entry = entry?;
- let path = entry.path();
-
- if path.is_dir() {
- let ns_name = path.file_name()
- .and_then(|n| n.to_str())
- .context("Invalid directory name")?;
-
- let full_ns = format!("{}.{}", prefix, ns_name);
- let mut endpoints = Vec::new();
-
- // Scan JSON files in this namespace
- for file_entry in fs::read_dir(&path)? {
- let file_entry = file_entry?;
- let file_path = file_entry.path();
-
- if file_path.extension().map(|e| e == "json").unwrap_or(false) {
- if let Some(endpoint) = parse_lexicon_file(&file_path)? {
- endpoints.push(endpoint);
- }
- }
- }
-
- if !endpoints.is_empty() {
- endpoints.sort_by(|a, b| a.nsid.cmp(&b.nsid));
- namespaces.insert(full_ns, endpoints);
- }
- }
- }
-
- Ok(())
-}
-
-fn parse_lexicon_file(path: &Path) -> Result