Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions skills/tinymind/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# TinyMind Blog Skill

Post thoughts, blog articles, and update about page to TinyMind (tinymind.me) using GitHub.

## Quick Start

```bash
# Set environment variables
export TINYMIND_REPO="your-username/tinymind-blog"

# Post a thought
./cli.sh thought "Hello world!"

# Post a blog article
./cli.sh blog "My Post" /path/to/post.md

# Update about page
./cli.sh about /path/to/about.md

# Upload an image
./cli.sh upload /path/to/image.png
```

## Requirements

- GitHub CLI (`gh`) authenticated with `repo` scope
- GitHub Personal Access Token with repo access

## Environment Variables

| Variable | Description | Default |
|----------|-------------|---------|
| `TINYMIND_REPO` | GitHub repository (format: `user/repo`) | `user/repo` |

## Commands

| Command | Description |
|---------|-------------|
| `thought "msg"` | Post a short thought |
| `thought "msg" image.jpg` | Post a thought with image |
| `blog "Title" file.md` | Post a blog article |
| `about file.md` | Update about page |
| `upload image.png` | Upload image, returns URL |

## Setup

1. Create a GitHub Personal Access Token with `repo` scope
2. Configure gh CLI: `gh auth login`
3. Set environment variable: `export TINYMIND_REPO="your-username/tinymind-blog"`
4. Authorize TinyMind to access your GitHub repository

## License

MIT
165 changes: 165 additions & 0 deletions skills/tinymind/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
---
name: tinymind
description: Post thoughts, blog articles, and update about page to TinyMind (tinymind.me) using GitHub. Use when managing TinyMind blog content, posting thoughts, writing blog posts, or updating profile images.
---

# TinyMind Blog Skill

Post thoughts, blog articles, and update about page to TinyMind (tinymind.me) using GitHub.

## Overview

TinyMind stores all content in a GitHub repository. This skill provides commands to:
- Post a thought (short message)
- Post a blog article (longer format with markdown)
- Update the About page
- Upload and link images
- Clean up unused images

## Configuration

Set environment variables:

```bash
export TINYMIND_USER="your-github-username"
export TINYMIND_REPO="your-username/tinymind-blog"
export TINYMIND_URL="https://tinymind.me"
```

## CLI Usage

### Post a Thought

```bash
{skillDir}/cli.sh thought "Your message here"
```

Example:
```bash
{skillDir}/cli.sh thought "今天天氣真好"
```

### Post a Thought with Image

```bash
{skillDir}/cli.sh thought "Message" /path/to/image.jpg
```

### Post a Blog Article

```bash
{skillDir}/cli.sh blog "Title" /path/to/article.md
```

### Update About Page

```bash
{skillDir}/cli.sh about /path/to/about.md
```

### Upload Image

```bash
{skillDir}/cli.sh upload /path/to/image.png
```

## Repository Structure

```
your-username/tinymind-blog/
├── content/
│ ├── about.md # About page content
│ ├── thoughts.json # Array of thought objects
│ └── blog/ # Markdown blog posts
│ └── post.md
└── assets/
└── images/
└── YYYY-MM-DD/
└── {timestamp}.png
```

## File Formats

### Thoughts (`thoughts.json`)

```json
[
{
"id": "1775464679964",
"content": "Your thought here...",
"timestamp": "2026-04-07T08:37:59.964Z"
}
]
```

### Blog Post

```yaml
---
title: Your Article Title
date: 2026-04-07T10:00:00.000Z
---

Your article content in markdown...

## Section

More content...
```

### About Page

Simple markdown file. Can include images.

```markdown
![Image](https://raw.githubusercontent.com/your-username/tinymind-blog/main/assets/images/YYYY-MM-DD/IMAGE_ID.png)

About content here...
```

## Image Workflow

### Step 1: Upload Image

```bash
# Download from URL
curl -sk "https://example.com/image.png" -o /tmp/image.png

# Upload to GitHub
DATE=$(date +%Y-%m-%d)
ID=$(date +%s%3N)
gh api -X PUT repos/${TINYMIND_REPO}/contents/assets/images/${DATE}/${ID}.png \
-F "content=$(base64 -w0 /tmp/image.png)" \
-F "message=Upload image"
```

### Step 2: Link Image in Content

Use the raw GitHub URL format:
```markdown
![Alt text](https://raw.githubusercontent.com/${TINYMIND_REPO}/main/assets/images/YYYY-MM-DD/IMAGE_ID.png)
```

## Cleaning Unused Images

Check which images are referenced in content:
```bash
curl -s https://raw.githubusercontent.com/${TINYMIND_REPO}/main/content/about.md | grep -oE 'assets/images/[^)]+\.(png|jpg|jpeg)'
curl -s https://raw.githubusercontent.com/${TINYMIND_REPO}/main/content/thoughts.json | grep -oE 'assets/images/[^)]+\.(png|jpg|jpeg)'
curl -s https://raw.githubusercontent.com/${TINYMIND_REPO}/main/content/blog/*.md | grep -oE 'assets/images/[^)]+\.(png|jpg|jpeg)'
```

Delete unused images:
```bash
SHA=$(gh api repos/${TINYMIND_REPO}/contents/assets/images/PATH/IMAGE.png --jq '.sha')
gh api -X DELETE repos/${TINYMIND_REPO}/contents/assets/images/PATH/IMAGE.png \
-F "message=Remove unused image" -F "sha=$SHA"
```

## Notes

- New thoughts are prepended to the thoughts list
- Images are uploaded to daily folders with timestamp-based IDs
- Timestamps are in ISO 8601 UTC format
- Markdown frontmatter uses `---` delimiters
- Image URLs must use `raw.githubusercontent.com` format
155 changes: 155 additions & 0 deletions skills/tinymind/cli.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
#!/bin/bash

# TinyMind Blog CLI
# Usage: tinymind-cli thought "message" [image]
# tinymind-cli blog "title" /path/to/markdown.md
# tinymind-cli about /path/to/content.md
# tinymind-cli upload /path/to/image.png

set -e

REPO="${TINYMIND_REPO:-user/repo}"
THOUGHTS_FILE="content/thoughts.json"
BLOG_DIR="content/blog"
ABOUT_FILE="content/about.md"
IMAGES_DIR="assets/images"

command -v gh >/dev/null 2>&1 || { echo "gh CLI required"; exit 1; }

post_thought() {
local message="$1"
local image="$2"
local timestamp now id img_url sha base64

timestamp=$(date -u +%Y-%m-%dT%H:%M:%S.000Z)
now=$(date +%s%3N)

if [ -n "$image" ]; then
local date_f
date_f=$(date +%Y-%m-%d)

# Upload image first
local img_content
img_content=$(base64 -w0 "$image")
gh api -X PUT "repos/$REPO/contents/${IMAGES_DIR}/${date_f}/${now}.png" \
-F "content=$img_content" \
-F "message=Upload image ${now}" \
-F "parents=$(gh api "repos/$REPO/git/main" --jq '.sha')" > /dev/null

img_url="https://raw.githubusercontent.com/$REPO/main/${IMAGES_DIR}/${date_f}/${now}.png"
fi

sha=$(gh api "repos/$REPO/contents/$THOUGHTS_FILE" --jq '.sha')

# Get current thoughts and add new one at beginning
local tmp_current tmp_new
tmp_current=$(mktemp)
tmp_new=$(mktemp)

curl -s "https://raw.githubusercontent.com/$REPO/main/$THOUGHTS_FILE" > "$tmp_current"

if [ -n "$img_url" ]; then
message="${message}"$'\n\n'"![image]($img_url)"
fi

jq --arg id "$now" --arg timestamp "$timestamp" --arg content "$message" \
'[{id: $id, content: $content, timestamp: $timestamp}] + .' "$tmp_current" > "$tmp_new"

base64=$(base64 -w0 "$tmp_new")

gh api -X PUT "repos/$REPO/contents/$THOUGHTS_FILE" \
-F "content=$base64" \
-F "message=Add thought via tinymind-cli" \
-F "sha=$sha"

rm -f "$tmp_current" "$tmp_new"

echo "Thought posted successfully"
}

post_blog() {
local title="$1"
local file="$2"
local filename sha base64 slug

# Create slug from title
slug=$(echo "$title" | tr '[:upper:]' '[:lower:]' | tr ' ' '-' | tr -d '[:punct:]')
filename="${slug}.md"

# Update date in frontmatter
local date_now
date_now=$(date -u +%Y-%m-%dT%H:%M:%S.000Z)

sed -i "s/^date:.*/date: $date_now/" "$file"

sha=$(gh api "repos/$REPO/contents/$BLOG_DIR/$filename" --jq '.sha' 2>/dev/null || echo "")

base64=$(base64 -w0 "$file")

if [ -z "$sha" ]; then
gh api -X PUT "repos/$REPO/contents/$BLOG_DIR/$filename" \
-F "content=$base64" \
-F "message=Add blog post: $title"
else
gh api -X PUT "repos/$REPO/contents/$BLOG_DIR/$filename" \
-F "content=$base64" \
-F "message=Update blog post: $title" \
-F "sha=$sha"
fi

echo "Blog post '$title' posted successfully"
}

update_about() {
local file="$1"
local sha base64

sha=$(gh api "repos/$REPO/contents/$ABOUT_FILE" --jq '.sha')
base64=$(base64 -w0 "$file")

gh api -X PUT "repos/$REPO/contents/$ABOUT_FILE" \
-F "content=$base64" \
-F "message=Update about page" \
-F "sha=$sha"

echo "About page updated successfully"
}

upload_image() {
local image="$1"
local date_f now img_url img_content

date_f=$(date +%Y-%m-%d)
now=$(date +%s%3N)

img_content=$(base64 -w0 "$image")
gh api -X PUT "repos/$REPO/contents/${IMAGES_DIR}/${date_f}/${now}.png" \
-F "content=$img_content" \
-F "message=Upload image ${now}" \
-F "parents=$(gh api "repos/$REPO/git/main" --jq '.sha')" > /dev/null

img_url="https://raw.githubusercontent.com/$REPO/main/${IMAGES_DIR}/${date_f}/${now}.png"
echo "$img_url"
}

case "$1" in
thought)
post_thought "$2" "$3"
;;
blog)
post_blog "$2" "$3"
;;
about)
update_about "$2"
;;
upload)
upload_image "$2"
;;
*)
echo "Usage: $0 thought \"message\" [image]"
echo " $0 blog \"title\" /path/to/markdown.md"
echo " $0 about /path/to/about.md"
echo " $0 upload /path/to/image.png"
exit 1
;;
esac