[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M71M5XFA19C97PYYMCXM1SKJ":3,"skill-same:01M71M5XFA19C97PYYMCXM1SKJ":74},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":15,"categories":16,"keywords":28,"publishedAt":48,"linkOnly":49,"markdownContent":50,"markdownBody":51,"frontMatter":52,"refName":53,"commitSha":54,"skillDirectory":55,"forksCount":56,"repositoryHtmlUrl":57,"repositoryHomepageUrl":6,"ownerHtmlUrl":58,"ownerBlogUrl":6,"ownerDescription":6,"updatedAt":59,"install":60,"resources":73},"01M71M5XFA19C97PYYMCXM1SKJ","pinme",null,"Use this skill when the user mentions \"pinme\", or needs to upload files, store to IPFS, create\u002Fpublish\u002Fdeploy websites or full-stack services (including frontend pages, backend APIs, database storage, email sending, etc.), or any feature requiring backend database\u002Fserver support.","developAgent\u002Fbmad-start","developAgent","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F264530239?v=4","01M71J8X6CY24V5ZZHFGETRMSW","01M71J8X739FS28DGQAAY7V4QR",1,"MIT","https:\u002F\u002Fgithub.com\u002FdevelopAgent\u002Fbmad-start\u002Fblob\u002Fmain\u002F.codemaker\u002Fskills\u002Fpinme\u002FSKILL.md",[17,22,25],{"categoryNo":18,"categoryName":19,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000005","邮件与沟通","SCENARIO","使用场景",{"categoryNo":23,"categoryName":24,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000009","前端开发",{"categoryNo":26,"categoryName":27,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000010","后端与接口",[5,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47],"support","services","store","upload","use","pages","email","feature","full","storage","ipfs","stack","server","create","publish","when","database","files","frontend","2026-11-10 10:56:23",false,"---\nname: pinme\ndescription: Use this skill when the user mentions \"pinme\", or needs to upload files, store to IPFS, create\u002Fpublish\u002Fdeploy websites or full-stack services (including frontend pages, backend APIs, database storage, email sending, etc.), or any feature requiring backend database\u002Fserver support.\n---\n\n# PinMe\n\nZero-config deployment tool: upload static files to IPFS, or create and deploy full-stack web projects (React+Vite + Cloudflare Worker + D1 database). Workers also support sending emails via the PinMe platform API.\n\n## When to Use\n\n```dot\ndigraph pinme_decision {\n    \"User Request\" [shape=doublecircle];\n    \"Needs backend API or database?\" [shape=diamond];\n    \"Upload Files (Path 1)\" [shape=box];\n    \"Full-Stack Project (Path 2)\" [shape=box];\n\n    \"User Request\" -> \"Needs backend API or database?\";\n    \"Needs backend API or database?\" -> \"Upload Files (Path 1)\" [label=\"No\"];\n    \"Needs backend API or database?\" -> \"Full-Stack Project (Path 2)\" [label=\"Yes\"];\n}\n```\n\n## Path 1: Upload Files \u002F Static Sites\n\n> Login required. Use `pinme login` or `pinme set-appkey \u003CAppKey>` before `pinme upload` or `pinme import`.\n\n```dot\ndigraph upload_flow {\n    \"Install\u002Fupdate pinme to latest\" [shape=box];\n    \"Authenticate\" [shape=box];\n    \"Determine build artifacts\" [shape=box];\n    \"pinme upload \u003Cpath>\" [shape=box];\n    \"Return preview URL\" [shape=doublecircle];\n\n    \"Install\u002Fupdate pinme to latest\" -> \"Authenticate\";\n    \"Authenticate\" -> \"Determine build artifacts\";\n    \"Determine build artifacts\" -> \"pinme upload \u003Cpath>\";\n    \"pinme upload \u003Cpath>\" -> \"Return preview URL\";\n}\n```\n\n**1. Check installation and update to latest:**\n```bash\nLOCAL=$(pinme --version 2>\u002Fdev\u002Fnull || echo \"0.0.0\")\nLATEST=$(npm view pinme version)\n[ \"$LOCAL\" != \"$LATEST\" ] && npm install -g pinme@latest || echo \"pinme is up to date ($LOCAL)\"\n```\n\n**2. Authenticate:**\n```bash\npinme login\n# or: pinme set-appkey \u003CAppKey>\n```\n\n**3. Determine upload target** (priority order):\n1. `dist\u002F` — Vite \u002F Vue \u002F React\n2. `build\u002F` — Create React App\n3. `out\u002F` — Next.js static export\n4. `public\u002F` — Plain static files\n\n**4. Upload:**\n```bash\npinme upload \u003Cpath>\npinme upload .\u002Fdist --domain my-site  # Optional: bind subdomain (wallet balance required)\n```\n\n**5. Return** the final URL printed by PinMe to the user. URL priority is: DNS domain > PinMe subdomain > short URL > preview URL. If it falls back to preview, return the **full URL** including all hash characters — do not truncate.\n\n### Common Examples\n\n```bash\npinme upload .\u002Fdocument.pdf          # Single file\npinme upload .\u002Fmy-folder             # Folder\npinme upload dist                    # Vite\u002FVue build artifacts\npinme upload build                   # CRA build artifacts\npinme upload out                     # Next.js static export\npinme upload .\u002Fdist --domain my-site # Bind PinMe subdomain (wallet balance required)\npinme import .\u002Fmy-archive.car        # Import CAR file\n```\n\n### Do NOT Upload\n- `node_modules\u002F`, `.env`, `.git\u002F`, `src\u002F`\n- Only upload build artifacts, never upload source code\n\n---\n\n## Path 2: Full-Stack Project\n\n> Login required. Uses React+Vite frontend + Cloudflare Worker backend + D1 SQLite database.\n> When designing frontend projects, use Ant Design as the primary design reference, and prioritize following its conventions for layout, components, spacing, and interaction patterns.\n\n```dot\ndigraph fullstack_flow {\n    \"Install\u002Fupdate pinme to latest\" [shape=box];\n    \"pinme login\" [shape=box];\n    \"pinme create \u003Cname>\" [shape=box];\n    \"Modify template code\" [shape=box];\n    \"pinme save\" [shape=box];\n    \"Return preview URL\" [shape=doublecircle];\n\n    \"Install\u002Fupdate pinme to latest\" -> \"pinme login\";\n    \"pinme login\" -> \"pinme create \u003Cname>\";\n    \"pinme create \u003Cname>\" -> \"Modify template code\";\n    \"Modify template code\" -> \"pinme save\";\n    \"pinme save\" -> \"Return preview URL\";\n}\n```\n\n### Architecture\n\n| Layer | Tech Stack | Deploy Target |\n|-------|-----------|---------------|\n| Frontend | React + Vite (`frontend\u002F`) | IPFS |\n| Backend | Cloudflare Worker (`backend\u002Fsrc\u002Fworker.ts`) | `{name}.pinme.pro` |\n| Database | D1 SQLite (`db\u002F*.sql`) | Cloudflare D1 |\n\n### Core Commands\n\n```bash\npinme login                  # Login (only needed once)\npinme create \u003CdirName>       # Clone template and create project (auto-fills API URL)\npinme save                   # First deploy \u002F full update (frontend + backend + database, single command)\npinme update-worker          # Update backend only (when only backend\u002Fsrc\u002Fworker.ts was modified)\npinme update-web             # Update frontend only (when only frontend\u002Fsrc\u002F was modified)\npinme update-db              # Run SQL migrations only (when only db\u002F was modified)\n```\n\n> `pinme save` deploys frontend + backend + database all at once. Only use `pinme update-*` when you're certain only one part was modified.\n\n### Project Structure\n\n```\n{project}\u002F\n├── pinme.toml              # Root config (auto-generated, do not modify)\n├── package.json            # Monorepo root (workspaces: frontend + backend)\n├── backend\u002F\n│   ├── wrangler.toml       # Worker config (auto-generated, do not modify)\n│   ├── package.json\n│   └── src\u002F\n│       └── worker.ts       # Backend entry — primarily used for JSON APIs in this template\n├── db\u002F\n│   └── 001_init.sql        # SQL table definitions\n├── frontend\u002F\n│   ├── package.json\n│   ├── vite.config.ts      # Dev proxy: \u002Fapi → localhost:8787\n│   ├── index.html\n│   ├── .env                # Auto-generated: VITE_API_URL (do not modify)\n│   └── src\u002F\n│       ├── main.tsx\n│       ├── App.tsx\n│       ├── utils\u002F\n│       │   ├── api.ts      # export const API = import.meta.env.VITE_WORKER_URL || ''\n│       │   └── config.ts   # Auto-generated: public_client_config (only when auth is enabled)\n│       └── pages\u002F\n│           └── Home\u002F\n│               └── index.tsx\n└── .gitignore\n```\n\n### First Deployment\n\n```bash\nLOCAL=$(pinme --version 2>\u002Fdev\u002Fnull || echo \"0.0.0\")\nLATEST=$(npm view pinme version)\n[ \"$LOCAL\" != \"$LATEST\" ] && npm install -g pinme@latest\npinme login\npinme create my-app\ncd my-app\n```\n\n`pinme create` generates a working Hello World template (includes frontend page + backend API routes + database schema). **Modify the template** to match the user's business logic — do not write from scratch:\n\n- Modify `backend\u002Fsrc\u002Fworker.ts` — replace API routes\n- Modify `frontend\u002Fsrc\u002Fpages\u002F` — replace page components\n- Modify `db\u002F001_init.sql` — replace table definitions\n\n```bash\npinme save\n# Single command deploys frontend + backend + database\n# Outputs preview URL: https:\u002F\u002Fpinme.eth.limo\u002F#\u002Fpreview\u002F{CID}\n```\n\n**Return** the preview URL to the user. Note: return the **full URL** including all hash characters — do not truncate.\n\nThe backend Worker is deployed at `https:\u002F\u002F{name}.pinme.pro`. Frontend API requests are automatically configured to point to that address — no manual setup needed.\n\n### Subsequent Updates\n\n| Changes | Command | Notes |\n|---------|---------|-------|\n| Backend only (`backend\u002Fsrc\u002Fworker.ts`) | `pinme update-worker` | Faster |\n| Frontend only (`frontend\u002Fsrc\u002F`) | `pinme update-web` | Generates new CID |\n| Database only (`db\u002F`) | `pinme update-db` | Runs new migrations |\n| Multiple changes or uncertain | `pinme save` | Safe full deployment |\n\n> Each frontend deployment generates a new CID and preview URL. Old URLs remain accessible.\n\n---\n\n## Worker Code Patterns (`backend\u002Fsrc\u002Fworker.ts`)\n\nIn this template, the Worker backend is primarily used for JSON APIs. Prefer standard Web APIs and simple manual routing by default. Worker-compatible libraries can be added when needed, but the default template does not rely on extra frameworks. Avoid packages that depend on a full Node.js runtime, a persistent local filesystem, native binaries, or child processes.\n\n```typescript\nexport interface Env {\n  DB: D1Database;           \u002F\u002F When using database\n  API_KEY?: string;         \u002F\u002F When using email sending\n  JWT_SECRET: string;       \u002F\u002F When using JWT auth\n  ADMIN_PASSWORD: string;   \u002F\u002F When using password auth\n}\n\nconst CORS_HEADERS = {\n  'Access-Control-Allow-Origin': '*',\n  'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',\n  'Access-Control-Allow-Headers': 'Content-Type, Authorization, X-API-Key',\n};\n\nfunction json(data: unknown, status = 200): Response {\n  return Response.json(data, { status, headers: CORS_HEADERS });\n}\n\nexport default {\n  async fetch(request: Request, env: Env): Promise\u003CResponse> {\n    const { pathname } = new URL(request.url);\n    const method = request.method;\n\n    if (method === 'OPTIONS') return new Response(null, { status: 204, headers: CORS_HEADERS });\n\n    try {\n      if (pathname === '\u002Fapi\u002Fitems' && method === 'GET')  return handleGetItems(env);\n      if (pathname === '\u002Fapi\u002Fitems' && method === 'POST') return handleCreateItem(request, env);\n      return json({ error: 'Not found' }, 404);\n    } catch {\n      return json({ error: 'Internal server error' }, 500);\n    }\n  },\n};\n```\n\n### Worker Constraints and Default Conventions\n\n| Item | Notes |\n|------|------|\n| Dependency choice | Prefer standard Web APIs and simple manual routing by default. If extra dependencies are needed, prefer Worker-compatible libraries. |\n| Node.js capability | Workers now support part of Node.js compatibility, but they are not a full Node.js runtime. Do not assume all Node.js built-in modules are available or behave exactly the same. |\n| Filesystem | Do not treat a Worker like a server with a persistent local disk. Even if some `fs` capabilities are available, do not rely on persistence across requests. |\n| Response types | This template mainly uses the Worker for JSON APIs. If there is a clear need, it can also be adapted to return HTML or other content. |\n| Password storage | Never store passwords in plaintext. Use a dedicated password hashing algorithm such as bcrypt, scrypt, or Argon2. |\n| SQL | Do not build SQL by string concatenation. Use parameterized queries such as `.bind()`. |\n\n### Email API Reference (for Worker Backend)\n\nWhen the backend needs email sending, use the PinMe platform API (`https:\u002F\u002Fpinme.cloud\u002Fapi\u002Fv4\u002Fsend_email`).\n\n**1. Configure API_KEY**\n\nAdd to the `Env` interface:\n\n```typescript\nexport interface Env {\n  DB: D1Database;\n  API_KEY?: string;  \u002F\u002F Required for email sending\n}\n```\n\n**2. Email Handler Code**\n\n```typescript\nasync function handleSendEmail(request: Request, env: Env): Promise\u003CResponse> {\n  const apiKey = env.API_KEY;\n  if (!apiKey) {\n    return json({ error: 'API_KEY not configured' }, 500);\n  }\n\n  const body = await request.json() as {\n    to?: string;\n    subject?: string;\n    html?: string;\n  };\n\n  if (!body.to) return json({ error: 'Email address is required' }, 400);\n  if (!body.subject) return json({ error: 'Subject is required' }, 400);\n  if (!body.html) return json({ error: 'HTML content is required' }, 400);\n\n  const emailRegex = \u002F^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$\u002F;\n  if (!emailRegex.test(body.to)) {\n    return json({ error: 'Invalid email address' }, 400);\n  }\n\n  const response = await fetch('https:\u002F\u002Fpinme.cloud\u002Fapi\u002Fv4\u002Fsend_email', {\n    method: 'POST',\n    headers: {\n      'Content-Type': 'application\u002Fjson',\n      'X-API-Key': apiKey,\n    },\n    body: JSON.stringify({\n      to: body.to,\n      subject: body.subject,\n      html: body.html,\n    }),\n  });\n\n  const result = await response.json();\n  return json(result);\n}\n```\n\n## Frontend API Utility (frontend\u002Fsrc\u002Futils\u002Fapi.ts)\n\n```typescript\n\u002F\u002F Development: Vite proxies \u002Fapi to localhost:8787\n\u002F\u002F Production: VITE_API_URL is auto-injected by pinme create\nexport const API = import.meta.env.VITE_API_URL || '';\n\nexport function getApiUrl(path: string): string {\n  return API ? `${API}${path}` : path;\n}\n```\n\n## D1 Database Operations\n\n```typescript\n\u002F\u002F Query multiple rows\nconst { results } = await env.DB.prepare('SELECT * FROM t WHERE x = ?').bind(val).all();\n\n\u002F\u002F Query single row (returns null if not found)\nconst row = await env.DB.prepare('SELECT * FROM t WHERE id = ?').bind(id).first();\n\n\u002F\u002F Insert and return new row\nconst row = await env.DB.prepare('INSERT INTO t (a, b) VALUES (?, ?) RETURNING *').bind(a, b).first();\n\n\u002F\u002F Update\nawait env.DB.prepare('UPDATE t SET a = ? WHERE id = ?').bind(val, id).run();\n\n\u002F\u002F Delete (check if affected)\nconst { meta } = await env.DB.prepare('DELETE FROM t WHERE id = ?').bind(id).run();\nif (meta.changes === 0) return json({ error: 'Not found' }, 404);\n```\n\n### SQL Migration Files\n\n**Format:** `db\u002FNNN_description.sql` (for example, `001_init.sql`). Files are executed in filename order.\n\n**SQLite Type Constraints:**\n\n| Do Not Use | Alternative |\n|-----------|-------------|\n| `BOOLEAN` | `INTEGER` (0 = false, 1 = true) |\n| `DATETIME` \u002F `TIMESTAMP` | `TEXT`, stored as ISO 8601 (default: `datetime('now')`) |\n| `JSON` type | `TEXT`, using `JSON.stringify()` \u002F `JSON.parse()` |\n| `VARCHAR(n)` | `TEXT` |\n\n## Template Architecture Suggestions\n\n| Scenario | Default Suggestion |\n|-----------|-------------|\n| File storage (image uploads) | Store external image URLs, or upload with `pinme upload` first and then store the resulting link |\n| Real-time communication | This template defaults to regular HTTP APIs. If there is no clear real-time requirement, start with polling |\n| Multiple Workers | This template defaults to combining functionality into a single Worker and separating routes by prefix |\n| Multiple databases | This template defaults to combining data into one D1 database and only splitting when isolation is truly needed |\n\n## Important Notes\n\n- `pinme.toml`, `backend\u002Fwrangler.toml`, and `frontend\u002F.env` are generated by PinMe. Do not edit them manually by default. If extra runtime configuration is truly needed, prefer doing it through PinMe-supported mechanisms.\n- Obtain the frontend API URL from the `VITE_API_URL` environment variable. Do not hardcode it.\n- Passwords, tokens, and API keys must be stored in secrets. Never put them in config files.\n\n## Common Errors\n\n| Error | Solution |\n|-------|----------|\n| `command not found: pinme` | `npm install -g pinme` |\n| `No such file or directory` | Verify that the path exists |\n| `Permission denied` | Check file or directory permissions |\n| Upload failed | Check the network connection and retry |\n| Not logged in | Run `pinme login` first |\n\n## Other Commands\n\n```bash\npinme list \u002F pinme ls -l 5     # View upload history\npinme list -c                  # Clear upload history\npinme rm \u003Chash>                # Delete uploaded content\npinme bind \u003Cpath> --domain \u003Cdomain>  # Bind domain (VIP + AppKey required)\npinme export \u003CCID>             # Export as CAR file\npinme set-appkey               # Set\u002Fview AppKey\npinme my-domains               # List bound domains\npinme delete \u003Cproject>          # Delete project (Worker + domain + D1)\npinme logout                   # Log out\n```\n","# PinMe\n\nZero-config deployment tool: upload static files to IPFS, or create and deploy full-stack web projects (React+Vite + Cloudflare Worker + D1 database). Workers also support sending emails via the PinMe platform API.\n\n## When to Use\n\n```dot\ndigraph pinme_decision {\n    \"User Request\" [shape=doublecircle];\n    \"Needs backend API or database?\" [shape=diamond];\n    \"Upload Files (Path 1)\" [shape=box];\n    \"Full-Stack Project (Path 2)\" [shape=box];\n\n    \"User Request\" -> \"Needs backend API or database?\";\n    \"Needs backend API or database?\" -> \"Upload Files (Path 1)\" [label=\"No\"];\n    \"Needs backend API or database?\" -> \"Full-Stack Project (Path 2)\" [label=\"Yes\"];\n}\n```\n\n## Path 1: Upload Files \u002F Static Sites\n\n> Login required. Use `pinme login` or `pinme set-appkey \u003CAppKey>` before `pinme upload` or `pinme import`.\n\n```dot\ndigraph upload_flow {\n    \"Install\u002Fupdate pinme to latest\" [shape=box];\n    \"Authenticate\" [shape=box];\n    \"Determine build artifacts\" [shape=box];\n    \"pinme upload \u003Cpath>\" [shape=box];\n    \"Return preview URL\" [shape=doublecircle];\n\n    \"Install\u002Fupdate pinme to latest\" -> \"Authenticate\";\n    \"Authenticate\" -> \"Determine build artifacts\";\n    \"Determine build artifacts\" -> \"pinme upload \u003Cpath>\";\n    \"pinme upload \u003Cpath>\" -> \"Return preview URL\";\n}\n```\n\n**1. Check installation and update to latest:**\n```bash\nLOCAL=$(pinme --version 2>\u002Fdev\u002Fnull || echo \"0.0.0\")\nLATEST=$(npm view pinme version)\n[ \"$LOCAL\" != \"$LATEST\" ] && npm install -g pinme@latest || echo \"pinme is up to date ($LOCAL)\"\n```\n\n**2. Authenticate:**\n```bash\npinme login\n# or: pinme set-appkey \u003CAppKey>\n```\n\n**3. Determine upload target** (priority order):\n1. `dist\u002F` — Vite \u002F Vue \u002F React\n2. `build\u002F` — Create React App\n3. `out\u002F` — Next.js static export\n4. `public\u002F` — Plain static files\n\n**4. Upload:**\n```bash\npinme upload \u003Cpath>\npinme upload .\u002Fdist --domain my-site  # Optional: bind subdomain (wallet balance required)\n```\n\n**5. Return** the final URL printed by PinMe to the user. URL priority is: DNS domain > PinMe subdomain > short URL > preview URL. If it falls back to preview, return the **full URL** including all hash characters — do not truncate.\n\n### Common Examples\n\n```bash\npinme upload .\u002Fdocument.pdf          # Single file\npinme upload .\u002Fmy-folder             # Folder\npinme upload dist                    # Vite\u002FVue build artifacts\npinme upload build                   # CRA build artifacts\npinme upload out                     # Next.js static export\npinme upload .\u002Fdist --domain my-site # Bind PinMe subdomain (wallet balance required)\npinme import .\u002Fmy-archive.car        # Import CAR file\n```\n\n### Do NOT Upload\n- `node_modules\u002F`, `.env`, `.git\u002F`, `src\u002F`\n- Only upload build artifacts, never upload source code\n\n---\n\n## Path 2: Full-Stack Project\n\n> Login required. Uses React+Vite frontend + Cloudflare Worker backend + D1 SQLite database.\n> When designing frontend projects, use Ant Design as the primary design reference, and prioritize following its conventions for layout, components, spacing, and interaction patterns.\n\n```dot\ndigraph fullstack_flow {\n    \"Install\u002Fupdate pinme to latest\" [shape=box];\n    \"pinme login\" [shape=box];\n    \"pinme create \u003Cname>\" [shape=box];\n    \"Modify template code\" [shape=box];\n    \"pinme save\" [shape=box];\n    \"Return preview URL\" [shape=doublecircle];\n\n    \"Install\u002Fupdate pinme to latest\" -> \"pinme login\";\n    \"pinme login\" -> \"pinme create \u003Cname>\";\n    \"pinme create \u003Cname>\" -> \"Modify template code\";\n    \"Modify template code\" -> \"pinme save\";\n    \"pinme save\" -> \"Return preview URL\";\n}\n```\n\n### Architecture\n\n| Layer | Tech Stack | Deploy Target |\n|-------|-----------|---------------|\n| Frontend | React + Vite (`frontend\u002F`) | IPFS |\n| Backend | Cloudflare Worker (`backend\u002Fsrc\u002Fworker.ts`) | `{name}.pinme.pro` |\n| Database | D1 SQLite (`db\u002F*.sql`) | Cloudflare D1 |\n\n### Core Commands\n\n```bash\npinme login                  # Login (only needed once)\npinme create \u003CdirName>       # Clone template and create project (auto-fills API URL)\npinme save                   # First deploy \u002F full update (frontend + backend + database, single command)\npinme update-worker          # Update backend only (when only backend\u002Fsrc\u002Fworker.ts was modified)\npinme update-web             # Update frontend only (when only frontend\u002Fsrc\u002F was modified)\npinme update-db              # Run SQL migrations only (when only db\u002F was modified)\n```\n\n> `pinme save` deploys frontend + backend + database all at once. Only use `pinme update-*` when you're certain only one part was modified.\n\n### Project Structure\n\n```\n{project}\u002F\n├── pinme.toml              # Root config (auto-generated, do not modify)\n├── package.json            # Monorepo root (workspaces: frontend + backend)\n├── backend\u002F\n│   ├── wrangler.toml       # Worker config (auto-generated, do not modify)\n│   ├── package.json\n│   └── src\u002F\n│       └── worker.ts       # Backend entry — primarily used for JSON APIs in this template\n├── db\u002F\n│   └── 001_init.sql        # SQL table definitions\n├── frontend\u002F\n│   ├── package.json\n│   ├── vite.config.ts      # Dev proxy: \u002Fapi → localhost:8787\n│   ├── index.html\n│   ├── .env                # Auto-generated: VITE_API_URL (do not modify)\n│   └── src\u002F\n│       ├── main.tsx\n│       ├── App.tsx\n│       ├── utils\u002F\n│       │   ├── api.ts      # export const API = import.meta.env.VITE_WORKER_URL || ''\n│       │   └── config.ts   # Auto-generated: public_client_config (only when auth is enabled)\n│       └── pages\u002F\n│           └── Home\u002F\n│               └── index.tsx\n└── .gitignore\n```\n\n### First Deployment\n\n```bash\nLOCAL=$(pinme --version 2>\u002Fdev\u002Fnull || echo \"0.0.0\")\nLATEST=$(npm view pinme version)\n[ \"$LOCAL\" != \"$LATEST\" ] && npm install -g pinme@latest\npinme login\npinme create my-app\ncd my-app\n```\n\n`pinme create` generates a working Hello World template (includes frontend page + backend API routes + database schema). **Modify the template** to match the user's business logic — do not write from scratch:\n\n- Modify `backend\u002Fsrc\u002Fworker.ts` — replace API routes\n- Modify `frontend\u002Fsrc\u002Fpages\u002F` — replace page components\n- Modify `db\u002F001_init.sql` — replace table definitions\n\n```bash\npinme save\n# Single command deploys frontend + backend + database\n# Outputs preview URL: https:\u002F\u002Fpinme.eth.limo\u002F#\u002Fpreview\u002F{CID}\n```\n\n**Return** the preview URL to the user. Note: return the **full URL** including all hash characters — do not truncate.\n\nThe backend Worker is deployed at `https:\u002F\u002F{name}.pinme.pro`. Frontend API requests are automatically configured to point to that address — no manual setup needed.\n\n### Subsequent Updates\n\n| Changes | Command | Notes |\n|---------|---------|-------|\n| Backend only (`backend\u002Fsrc\u002Fworker.ts`) | `pinme update-worker` | Faster |\n| Frontend only (`frontend\u002Fsrc\u002F`) | `pinme update-web` | Generates new CID |\n| Database only (`db\u002F`) | `pinme update-db` | Runs new migrations |\n| Multiple changes or uncertain | `pinme save` | Safe full deployment |\n\n> Each frontend deployment generates a new CID and preview URL. Old URLs remain accessible.\n\n---\n\n## Worker Code Patterns (`backend\u002Fsrc\u002Fworker.ts`)\n\nIn this template, the Worker backend is primarily used for JSON APIs. Prefer standard Web APIs and simple manual routing by default. Worker-compatible libraries can be added when needed, but the default template does not rely on extra frameworks. Avoid packages that depend on a full Node.js runtime, a persistent local filesystem, native binaries, or child processes.\n\n```typescript\nexport interface Env {\n  DB: D1Database;           \u002F\u002F When using database\n  API_KEY?: string;         \u002F\u002F When using email sending\n  JWT_SECRET: string;       \u002F\u002F When using JWT auth\n  ADMIN_PASSWORD: string;   \u002F\u002F When using password auth\n}\n\nconst CORS_HEADERS = {\n  'Access-Control-Allow-Origin': '*',\n  'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',\n  'Access-Control-Allow-Headers': 'Content-Type, Authorization, X-API-Key',\n};\n\nfunction json(data: unknown, status = 200): Response {\n  return Response.json(data, { status, headers: CORS_HEADERS });\n}\n\nexport default {\n  async fetch(request: Request, env: Env): Promise\u003CResponse> {\n    const { pathname } = new URL(request.url);\n    const method = request.method;\n\n    if (method === 'OPTIONS') return new Response(null, { status: 204, headers: CORS_HEADERS });\n\n    try {\n      if (pathname === '\u002Fapi\u002Fitems' && method === 'GET')  return handleGetItems(env);\n      if (pathname === '\u002Fapi\u002Fitems' && method === 'POST') return handleCreateItem(request, env);\n      return json({ error: 'Not found' }, 404);\n    } catch {\n      return json({ error: 'Internal server error' }, 500);\n    }\n  },\n};\n```\n\n### Worker Constraints and Default Conventions\n\n| Item | Notes |\n|------|------|\n| Dependency choice | Prefer standard Web APIs and simple manual routing by default. If extra dependencies are needed, prefer Worker-compatible libraries. |\n| Node.js capability | Workers now support part of Node.js compatibility, but they are not a full Node.js runtime. Do not assume all Node.js built-in modules are available or behave exactly the same. |\n| Filesystem | Do not treat a Worker like a server with a persistent local disk. Even if some `fs` capabilities are available, do not rely on persistence across requests. |\n| Response types | This template mainly uses the Worker for JSON APIs. If there is a clear need, it can also be adapted to return HTML or other content. |\n| Password storage | Never store passwords in plaintext. Use a dedicated password hashing algorithm such as bcrypt, scrypt, or Argon2. |\n| SQL | Do not build SQL by string concatenation. Use parameterized queries such as `.bind()`. |\n\n### Email API Reference (for Worker Backend)\n\nWhen the backend needs email sending, use the PinMe platform API (`https:\u002F\u002Fpinme.cloud\u002Fapi\u002Fv4\u002Fsend_email`).\n\n**1. Configure API_KEY**\n\nAdd to the `Env` interface:\n\n```typescript\nexport interface Env {\n  DB: D1Database;\n  API_KEY?: string;  \u002F\u002F Required for email sending\n}\n```\n\n**2. Email Handler Code**\n\n```typescript\nasync function handleSendEmail(request: Request, env: Env): Promise\u003CResponse> {\n  const apiKey = env.API_KEY;\n  if (!apiKey) {\n    return json({ error: 'API_KEY not configured' }, 500);\n  }\n\n  const body = await request.json() as {\n    to?: string;\n    subject?: string;\n    html?: string;\n  };\n\n  if (!body.to) return json({ error: 'Email address is required' }, 400);\n  if (!body.subject) return json({ error: 'Subject is required' }, 400);\n  if (!body.html) return json({ error: 'HTML content is required' }, 400);\n\n  const emailRegex = \u002F^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$\u002F;\n  if (!emailRegex.test(body.to)) {\n    return json({ error: 'Invalid email address' }, 400);\n  }\n\n  const response = await fetch('https:\u002F\u002Fpinme.cloud\u002Fapi\u002Fv4\u002Fsend_email', {\n    method: 'POST',\n    headers: {\n      'Content-Type': 'application\u002Fjson',\n      'X-API-Key': apiKey,\n    },\n    body: JSON.stringify({\n      to: body.to,\n      subject: body.subject,\n      html: body.html,\n    }),\n  });\n\n  const result = await response.json();\n  return json(result);\n}\n```\n\n## Frontend API Utility (frontend\u002Fsrc\u002Futils\u002Fapi.ts)\n\n```typescript\n\u002F\u002F Development: Vite proxies \u002Fapi to localhost:8787\n\u002F\u002F Production: VITE_API_URL is auto-injected by pinme create\nexport const API = import.meta.env.VITE_API_URL || '';\n\nexport function getApiUrl(path: string): string {\n  return API ? `${API}${path}` : path;\n}\n```\n\n## D1 Database Operations\n\n```typescript\n\u002F\u002F Query multiple rows\nconst { results } = await env.DB.prepare('SELECT * FROM t WHERE x = ?').bind(val).all();\n\n\u002F\u002F Query single row (returns null if not found)\nconst row = await env.DB.prepare('SELECT * FROM t WHERE id = ?').bind(id).first();\n\n\u002F\u002F Insert and return new row\nconst row = await env.DB.prepare('INSERT INTO t (a, b) VALUES (?, ?) RETURNING *').bind(a, b).first();\n\n\u002F\u002F Update\nawait env.DB.prepare('UPDATE t SET a = ? WHERE id = ?').bind(val, id).run();\n\n\u002F\u002F Delete (check if affected)\nconst { meta } = await env.DB.prepare('DELETE FROM t WHERE id = ?').bind(id).run();\nif (meta.changes === 0) return json({ error: 'Not found' }, 404);\n```\n\n### SQL Migration Files\n\n**Format:** `db\u002FNNN_description.sql` (for example, `001_init.sql`). Files are executed in filename order.\n\n**SQLite Type Constraints:**\n\n| Do Not Use | Alternative |\n|-----------|-------------|\n| `BOOLEAN` | `INTEGER` (0 = false, 1 = true) |\n| `DATETIME` \u002F `TIMESTAMP` | `TEXT`, stored as ISO 8601 (default: `datetime('now')`) |\n| `JSON` type | `TEXT`, using `JSON.stringify()` \u002F `JSON.parse()` |\n| `VARCHAR(n)` | `TEXT` |\n\n## Template Architecture Suggestions\n\n| Scenario | Default Suggestion |\n|-----------|-------------|\n| File storage (image uploads) | Store external image URLs, or upload with `pinme upload` first and then store the resulting link |\n| Real-time communication | This template defaults to regular HTTP APIs. If there is no clear real-time requirement, start with polling |\n| Multiple Workers | This template defaults to combining functionality into a single Worker and separating routes by prefix |\n| Multiple databases | This template defaults to combining data into one D1 database and only splitting when isolation is truly needed |\n\n## Important Notes\n\n- `pinme.toml`, `backend\u002Fwrangler.toml`, and `frontend\u002F.env` are generated by PinMe. Do not edit them manually by default. If extra runtime configuration is truly needed, prefer doing it through PinMe-supported mechanisms.\n- Obtain the frontend API URL from the `VITE_API_URL` environment variable. Do not hardcode it.\n- Passwords, tokens, and API keys must be stored in secrets. Never put them in config files.\n\n## Common Errors\n\n| Error | Solution |\n|-------|----------|\n| `command not found: pinme` | `npm install -g pinme` |\n| `No such file or directory` | Verify that the path exists |\n| `Permission denied` | Check file or directory permissions |\n| Upload failed | Check the network connection and retry |\n| Not logged in | Run `pinme login` first |\n\n## Other Commands\n\n```bash\npinme list \u002F pinme ls -l 5     # View upload history\npinme list -c                  # Clear upload history\npinme rm \u003Chash>                # Delete uploaded content\npinme bind \u003Cpath> --domain \u003Cdomain>  # Bind domain (VIP + AppKey required)\npinme export \u003CCID>             # Export as CAR file\npinme set-appkey               # Set\u002Fview AppKey\npinme my-domains               # List bound domains\npinme delete \u003Cproject>          # Delete project (Worker + domain + D1)\npinme logout                   # Log out\n```\n",{"name":5,"description":7},"main","1907bbe850fb749efa8b499b8da7ebb78a663519",".codemaker\u002Fskills\u002Fpinme",0,"https:\u002F\u002Fgithub.com\u002FdevelopAgent\u002Fbmad-start","https:\u002F\u002Fgithub.com\u002FdevelopAgent","2026-07-19 05:19:22",{"source":8,"skillName":5,"commands":61,"prompt":71,"zipAvailable":72},[62,65,68],{"tool":63,"command":64},"npx","npx skills add developAgent\u002Fbmad-start --skill pinme",{"tool":66,"command":67},"bunx","bunx skills add developAgent\u002Fbmad-start --skill pinme",{"tool":69,"command":70},"pnpm","pnpm dlx skills add developAgent\u002Fbmad-start --skill pinme","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FdevelopAgent\u002Fbmad-start\u002Fblob\u002Fmain\u002F.codemaker\u002Fskills\u002Fpinme\u002FSKILL.md",true,[],[75,97,127,145,159,185],{"skillNo":76,"name":77,"nameZh":6,"description":78,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":79,"categories":80,"keywords":86,"publishedAt":96},"01M71R3M9DJTTY0ARFQ6K04NMP","gds-correct-course","Manage significant changes during sprint execution. Use when the user says \"correct course\" or \"propose sprint change\"","https:\u002F\u002Fgithub.com\u002FdevelopAgent\u002Fbmad-start\u002Fblob\u002Fmain\u002F.rovodev\u002Fskills\u002Fgds-correct-course\u002FSKILL.md",[81],{"categoryNo":82,"categoryName":83,"taxonomyType":84,"taxonomyTypeDesc":85},"01JBSEEDCAT000000000000039","教师与教育","PROFESSION","适用职业",[87,88,89,90,91,92,44,33,93,94,95],"gds correct course","course","correct","user","changes","change","execution","manage","sprint","2026-11-10 13:02:02",{"skillNo":98,"name":99,"nameZh":6,"description":100,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":101,"categories":102,"keywords":109,"publishedAt":96},"01M71R3GENSFD1A1XVZTTQG1KF","gds-code-review","Review code changes adversarially using parallel review layers (Blind Hunter, Edge Case Hunter, Acceptance Auditor) with structured triage into actionable categories. Use when the user says \"run code review\" or \"review this code\"","https:\u002F\u002Fgithub.com\u002FdevelopAgent\u002Fbmad-start\u002Fblob\u002Fmain\u002F.rovodev\u002Fskills\u002Fgds-code-review\u002FSKILL.md",[103,106],{"categoryNo":104,"categoryName":105,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000007","代码审查",{"categoryNo":107,"categoryName":108,"taxonomyType":84,"taxonomyTypeDesc":85},"01JBSEEDCAT000000000000030","开发工程师",[110,111,112,113,114,91,115,116,117,118,119,120,121,44,122,33,123,124,125,126],"code review","code","review","gds code review","categories","triage","review code","run","parallel","case","with","run code","acceptance","edge","actionable","layers","hunter",{"skillNo":128,"name":129,"nameZh":6,"description":130,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":131,"categories":132,"keywords":133,"publishedAt":96},"01M71R3DD098MQRD6F8S4GG0AW","gds-check-implementation-readiness","Verify GDD, UX, Architecture, and Epics alignment before production. Use when the user says \"check readiness\" or \"implementation readiness\"","https:\u002F\u002Fgithub.com\u002FdevelopAgent\u002Fbmad-start\u002Fblob\u002Fmain\u002F.rovodev\u002Fskills\u002Fgds-check-implementation-readiness\u002FSKILL.md",[],[134,135,136,137,138,139,90,140,141,142,143,44,33,144],"check","readiness","Implementation Readiness","gds check implementation readiness","implementation","check readiness","Production","ux","verify","architecture","alignment",{"skillNo":146,"name":147,"nameZh":6,"description":148,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":149,"categories":150,"keywords":151,"publishedAt":96},"01M71R3ACAA1G0NVQ330JQNJPK","gds-brainstorm-game","Facilitate game brainstorming sessions with game-specific techniques. Use when the user says \"brainstorm game\" or \"game ideas\"","https:\u002F\u002Fgithub.com\u002FdevelopAgent\u002Fbmad-start\u002Fblob\u002Fmain\u002F.rovodev\u002Fskills\u002Fgds-brainstorm-game\u002FSKILL.md",[],[152,153,154,90,155,120,44,33,156,157,158],"gds brainstorm game","game","brainstorm","brainstorming","techniques","sessions","ideas",{"skillNo":160,"name":161,"nameZh":6,"description":162,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":163,"categories":164,"keywords":168,"publishedAt":96},"01M71R377MJ6WJTTFARGKH3HX7","gds-agent-tech-writer","Technical documentation specialist and knowledge curator for game projects. Use when the user asks to talk to Paige or requests the Technical Writer.","https:\u002F\u002Fgithub.com\u002FdevelopAgent\u002Fbmad-start\u002Fblob\u002Fmain\u002F.rovodev\u002Fskills\u002Fgds-agent-tech-writer\u002FSKILL.md",[165],{"categoryNo":166,"categoryName":167,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000023","Skill与智能体开发",[169,170,171,172,33,173,174,175,176,44,90,177,178,179,180,181,182,183,153,184],"gds agent tech writer","tech","writer","technical writer","technical","knowledge","for","projects","technical documentation","talk","specialist","documentation specialist","knowledge curator","requests","documentation","curator",{"skillNo":186,"name":187,"nameZh":6,"description":188,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":189,"categories":190,"keywords":192,"publishedAt":96},"01M71R34RGT2ZX3TSFA2CRT0NC","gds-agent-game-solo-dev","Elite indie game developer for rapid prototyping and solo quick-flow development. Use when the user asks to talk to Indie or requests the Game Solo Dev.","https:\u002F\u002Fgithub.com\u002FdevelopAgent\u002Fbmad-start\u002Fblob\u002Fmain\u002F.rovodev\u002Fskills\u002Fgds-agent-game-solo-dev\u002FSKILL.md",[191],{"categoryNo":166,"categoryName":167,"taxonomyType":20,"taxonomyTypeDesc":21},[193,153,194,195,196,197,90,178,182,198,199,44,33,200,175,201,202],"solo","gds agent game solo dev","dev","flow","developer","RAPID","game developer","prototyping","development","quick"]