1
0
mirror of https://github.com/misskey-dev/misskey.git synced 2026-06-17 21:04:51 +02:00

Compare commits

..

11 Commits

Author SHA1 Message Date
syuilo
2402754dcc Update pizzax.ts 2025-03-10 21:44:23 +09:00
syuilo
2493592bd0 wip 2025-03-10 12:08:42 +09:00
syuilo
eec4ab841a Merge branch 'develop' into refine-pizzax 2025-03-10 11:29:16 +09:00
syuilo
d0b8ffe629 Merge branch 'develop' into refine-pizzax 2025-03-10 11:28:13 +09:00
syuilo
cef7575b76 commit 2025-03-10 11:23:15 +09:00
syuilo
9842eb2eeb wip 2025-03-10 11:21:17 +09:00
syuilo
05078e9c14 wip 2025-03-10 11:17:08 +09:00
syuilo
db5c6fa3c2 wip 2025-03-10 11:13:33 +09:00
syuilo
8a4e2659ed Merge branch 'develop' into refine-pizzax 2025-03-10 11:10:32 +09:00
syuilo
d19c094a9b refactor(frontend): rename pizzax fields 2025-03-10 11:09:59 +09:00
syuilo
a7f7ff33e7 wip 2025-03-10 10:47:50 +09:00
1870 changed files with 86905 additions and 145909 deletions

2
.claude/.gitignore vendored
View File

@@ -1,2 +0,0 @@
/settings.local.json
/.credentials.json

View File

@@ -1,76 +0,0 @@
# Third-Party Licenses (`.claude/`)
`.claude/` 配下ãĢ取りčžŧぞれãĻいるã‚ĩãƒŧドパãƒŧãƒ†ã‚Ŗį”ąæĨã‚ŗãƒŗãƒãƒŧãƒãƒŗãƒˆãŽãƒŠã‚¤ã‚ģãƒŗã‚šãƒģå‡ēå…¸æƒ…å ąã‚’ãžã¨ã‚ã‚‹ã€‚Misskey æœŦäŊ“は AGPL-3.0-only だが、æœŦãƒ‡ã‚ŖãƒŦクトãƒĒ内ãĢは MIT ナイã‚ģãƒŗã‚šãŽãƒ•ã‚Ąã‚¤ãƒĢがåĢぞれãĻã„ã‚‹ã€‚å„ãƒ•ã‚Ąã‚¤ãƒĢ冒頭ãĢも `SPDX-License-Identifier` とå‡ēå…¸ã‚ŗãƒĄãƒŗãƒˆã‚’äŊĩč¨˜ã—ãĻいる。
最įĩ‚æ›´æ–°: 2026-05-11
---
## 1. everything-claude-code (ECC)
- 上æĩãƒĒポジトãƒĒ: <https://github.com/affaan-m/everything-claude-code>
- 取りčžŧんだバãƒŧã‚¸ãƒ§ãƒŗ: v2.0.0-rc.1
- ナイã‚ģãƒŗã‚š: **MIT**
- Copyright: Copyright (c) 2026 Affaan Mustafa
### 取りčžŧã‚“ã ãƒ•ã‚Ąã‚¤ãƒĢ
| `.claude/` 内ぎパ゚ | 上æĩãƒ‘゚ | 上æĩ frontmatter `origin` | Misskey でぎ攚変 |
|---|---|---|---|
| `skills/context-budget/SKILL.md` | `skills/context-budget/SKILL.md` | ECC | description をæ—ĨæœŦčĒžåŒ–ã€Misskey å›ēæœ‰ãƒĄãƒĸをčŋŊ記 |
| `commands/harness-audit.md` | `commands/harness-audit.md` | ECC | scripts 䞝存ぎč‡Ēå‹•æŽĄį‚šã‚’ã€Claude が `pnpm`/`git`/`grep` ã§æ‰‹å‹•æŽĄį‚šã™ã‚‹į‰ˆãĢ書き換え。Misskey å›ēæœ‰ãŽčŠ•äžĄčģ¸ (SPDX / endpoint-list / migration / locales) をįĩ„ãŋčžŧãŋ |
| `commands/quality-gate.md` | `commands/quality-gate.md` | ECC | 言čĒžč‡Ē動判厚を排除し Misskey å›ē厚 pipeline (`pnpm` + tsgo + ESLint + Vitest) ãĢ。Prettier/Biome フェãƒŧã‚ēを削除 |
### MIT License (full text)
```
MIT License
Copyright (c) 2026 Affaan Mustafa
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
```
### 上æĩ LICENSE ãƒ•ã‚Ąã‚¤ãƒĢ
<https://github.com/affaan-m/everything-claude-code/blob/main/LICENSE>
---
## 2. AGPL ã‚ŗãƒŧドベãƒŧ゚とぎäē’æ›æ€§
Misskey æœŦäŊ“は **AGPL-3.0-only** で配布されãĻいるが、`.claude/` 配下ぎ MIT ナイã‚ģãƒŗã‚šãƒ•ã‚Ąã‚¤ãƒĢはそぎぞぞ MIT としãĻ掋しãĻいる。
- MIT は permissive ナイã‚ģãƒŗã‚šã§ã€AGPL をåĢむ copyleft ナイã‚ģãƒŗã‚šãŽãƒ—ãƒ­ã‚¸ã‚§ã‚¯ãƒˆãĢ **取りčžŧãŋãƒģå†é…å¸ƒãŒč¨ąã•ã‚Œã‚‹**
- MIT がčĻæą‚ã™ã‚‹æĄäģļ (copyright notice + license text ぎäŋæŒ) をæœŦãƒ•ã‚Ąã‚¤ãƒĢ + å„ãƒ•ã‚Ąã‚¤ãƒĢ冒頭ぎ SPDX/å‡ēå…¸ã‚ŗãƒĄãƒŗãƒˆã§æē€ãŸã—ãĻいる
- Misskey 全äŊ“ãŽé…å¸ƒį‰Šã¨ã—ãĻは AGPL-3.0-only ã§æ‰ąã‚ã‚Œã‚‹ãŒã€`.claude/` 配下ぎ MIT ãƒ•ã‚Ąã‚¤ãƒĢは個åˆĨãĢ MIT としãĻ識åˆĨ可čƒŊ
`.ts` / `.js` / `.vue` / `.scss` ぎ SPDX įžŠå‹™åŒ– ([AGENTS.md §1](../AGENTS.md#1-spdx-ヘッダãƒŧåŋ…é ˆ)) は Misskey æœŦäŊ“ã‚ŗãƒŧド向けで、`.claude/` 配下ぎ `.md` / `.sh` ãĢã¯éŠį”¨ã•ã‚ŒãĒい。
---
## 3. 新čĻčŋŊ加時ぎ手順
`.claude/` ãĢ新たãĢã‚ĩãƒŧドパãƒŧãƒ†ã‚Ŗį”ąæĨãŽãƒ•ã‚Ąã‚¤ãƒĢを取りčžŧむ際は:
1. ナイã‚ģãƒŗã‚šã‚’įĸēčĒ (äē’æ›æ€§: MIT / Apache-2.0 / BSD は OK、GPL/AGPL はčρᛏč̇)
2. å„ãƒ•ã‚Ąã‚¤ãƒĢ冒頭ãĢ SPDX ヘッダ + å‡ēå…¸ã‚ŗãƒĄãƒŗãƒˆã‚’čŋŊ加
3. æœŦãƒ•ã‚Ąã‚¤ãƒĢ §1 ぎテãƒŧブãƒĢãĢ 1 行čŋŊ記
4. åŋ…čρãĒら新しいã‚ģã‚¯ã‚ˇãƒ§ãƒŗã§ãƒŠã‚¤ã‚ģãƒŗã‚šå…¨æ–‡ã‚’åŒæĸą
5. AGENTS.md ã‹ã‚‰ãŽå‚į…§ã‚’įĸēčĒ (įžįŠļぎ [AGENTS.md §ツãƒŧãƒĢå›ēæœ‰ãŽčŖœåŠŠãƒ•ã‚Ąã‚¤ãƒĢ](../AGENTS.md) で `THIRD_PARTY_LICENSES.md` ã‚’æĄˆå†…æ¸ˆã€‚CLAUDE.md は `@AGENTS.md` įĩŒį”ąã§čĒ­ãŋčžŧむぎで個åˆĨぎčŋŊč¨˜ã¯ä¸čρ)

View File

@@ -1,23 +0,0 @@
# `.claude/agents/` — プロジェクトå›ē有ぎã‚ĩブエãƒŧã‚¸ã‚§ãƒŗãƒˆ
Misskey ãŽį‰šåŽšé ˜åŸŸãĢį‰šåŒ–ã—ãŸãƒŦビãƒĨãƒŧ / čĒŋæŸģエãƒŧã‚¸ã‚§ãƒŗãƒˆã‚’ `.claude/agents/<name>.md` åŊĸåŧã§é…įŊŽã™ã‚‹ã€‚
frontmatter (`name` + `description` + `tools`) は、Claude が **č‡Ē動でエãƒŧã‚¸ã‚§ãƒŗãƒˆã‚’å‘ŧãŗå‡ēすか判断する** 唯一ぎ手がかりãĢãĒる。`description` ãĢã¯į”¨é€”ã‚’å…ˇäŊ“įš„ã‹ã¤įļ˛įž…įš„ãĢ書くこと (å‹•čŠž + å¯žčąĄ + トãƒĒã‚ŦãƒŧæĄäģļ)。
## åŽŸčŖ…æ¸ˆã‚ĩブエãƒŧã‚¸ã‚§ãƒŗãƒˆ
| エãƒŧã‚¸ã‚§ãƒŗãƒˆå | åŊšå‰˛ | å„Ē先åēĻ |
|---|---|---|
| [misskey-api-reviewer](misskey-api-reviewer.md) | NestJS DI + meta/paramDef + UUID 重複 + endpoint-list.ts į™ģ錞 + ApiError throw + misskey-js å†į”Ÿæˆ + e2e + CHANGELOG をチェック | é̘ (į™ģ錞æŧã‚Œã§ 404 / autogen CI čŊãĄé ģį™ē) |
| [vue-component-reviewer](vue-component-reviewer.md) | Mk\* å‘Ŋ名 / `<script lang="ts" setup>` / type-only defineProps / SCSS module / CSS 変数 / i18n.ts と i18n.tsx ぎäŊŋい分け / os.\* įĩŒį”ą / a11y / `*.stories.impl.ts` äŊĩč¨­ã‚’ãƒã‚§ãƒƒã‚¯ | 中 (CI į›´æ’ƒã¯ SPDX / locales įˇ¨é›†é•åãŽãŋ。äģ–ã¯åŽŸåŽŗãŒå‡ēãĻから検å‡ēã•ã‚Œã‚‹ã‚ąãƒŧ゚が多く API ãģãŠãŽåŗæ­ģ性はãĒい) |
č¨­č¨ˆæ–šé‡: `tools` ã‚’įˇ¨é›†æ¨Šé™ãĒし (Edit/Write ã‚’æ¸Ąã•ãĒい) ãĢįĩžã‚Šã€PR baseline (`git merge-base origin/develop HEAD`) ã¨ãŽåˇŽåˆ†ã‹ã‚‰č‡Ēå‹•įš„ãĢãƒŦビãƒĨãƒŧå¯žčąĄã‚’æŠŊå‡ēする。
## 新čĻã‚¨ãƒŧã‚¸ã‚§ãƒŗãƒˆã‚’čŋŊ加する場合
- `.claude/agents/<name>.md` ãĢ YAML frontmatter (`name` / `description` / `tools`) とæœŦ文 Markdown を書く。
- `description` はå‘ŧãŗå‡ēし判断ãĢäŊŋã‚ã‚Œã‚‹ãŸã‚ã€å¯žčąĄãƒ‰ãƒĄã‚¤ãƒŗãƒģä¸ģčĻãƒã‚§ãƒƒã‚¯é …į›ŽãƒģトãƒĒã‚ŦãƒŧæĄäģļを **å…ˇäŊ“įš„ãĢ** 列挙する。
- ãƒŦビãƒĨãƒŧ専門ãĒら `tools: Read, Grep, Glob, Bash` ãĢįĩžã‚‹ (Edit/Write ã‚’æ¸Ąã•ãĒい)。**`Bash` はäģģæ„ãŽã‚ˇã‚§ãƒĢã‚ŗãƒžãƒŗãƒ‰ã‚’åŽŸčĄŒã§ãã‚‹åŧˇåŠ›ãĒæ¨Šé™ã§ã‚ã‚‹į‚šãĢæŗ¨æ„**: ãƒŦビãƒĨãƒŧį”¨é€”ã§ã¯ `git diff` / `git ls-files` / `grep` / `sed` į­‰ãŽ **čĒ­ãŋ取りįŗģã‚ŗãƒžãƒŗãƒ‰ãĢ限厚しãĻäŊŋう** こと。書きčžŧãŋãƒģ削除ãƒģネットワãƒŧク送äŋĄã‚’äŧ´ã†æ“äŊœã¯æœŦ文中ぎ䞋į¤ēãƒģ指į¤ēãĢåĢめãĒいこと (エãƒŧã‚¸ã‚§ãƒŗãƒˆæœŦ文がã‚ŦãƒŧドãƒŦãƒŧãƒĢãĢãĒる)。
- ä¸ģčĻå‚į…§ãƒ•ã‚Ąã‚¤ãƒĢへぎãƒĒãƒŗã‚¯ã¯ã€ãƒĒポジトãƒĒãƒĢãƒŧãƒˆã‹ã‚‰ãŽį›¸å¯žãƒ‘ã‚š (例: `../../packages/backend/...`) でč˛ŧる。įĩļ寞パ゚は contributor ぎホãƒŧãƒ ãƒ‡ã‚ŖãƒŦクトãƒĒ䞝存ãĢãĒるぎでäŊŋわãĒい。
- åˇŽåˆ†æŠŊå‡ēは `git merge-base origin/develop HEAD` を baseline ãĢする (PR / ãƒ–ãƒŠãƒŗãƒå…¨äŊ“ã‚’čĻ‹ã‚‹ãŸã‚)。`git diff HEAD` 単äŊ“は **æœĒã‚ŗãƒŸãƒƒãƒˆåˇŽåˆ†ã—ã‹å–ã‚Œãšã€ã‚ŗãƒŸãƒƒãƒˆæ¸ˆãŽ PR ではįŠēãĢãĒãŖãĻčĒ¤åˆ¤åŽšã™ã‚‹** ぎでäŊŋわãĒい。
- 厌成したらこぎ README ãŽčĄ¨ãĢも 1 行čŋŊ加する。

View File

@@ -1,167 +0,0 @@
---
name: misskey-api-reviewer
description: Misskey ぎ API ã‚¨ãƒŗãƒ‰ãƒã‚¤ãƒŗãƒˆ (packages/backend/src/server/api/endpoints/) ぎčŋŊ加ãƒģ変更を専門ãƒŦビãƒĨãƒŧする。SPDX / meta / paramDef / UUID 重複 / endpoint-list.ts į™ģ錞 / ApiError throw / misskey-js å†į”Ÿæˆ / e2e / CHANGELOG を抟æĸ°įš„ãĢãƒã‚§ãƒƒã‚¯ã€‚ãƒãƒƒã‚¯ã‚¨ãƒŗãƒ‰ API をčŋŊ加ãƒģ変更した PR ãƒŦビãƒĨãƒŧでå‘ŧãŗå‡ēす。
tools: Read, Grep, Glob, Bash
---
# Misskey API ã‚¨ãƒŗãƒ‰ãƒã‚¤ãƒŗãƒˆãƒŦビãƒĨã‚ĸãƒŧ
Misskey ãƒãƒƒã‚¯ã‚¨ãƒŗãƒ‰ (`packages/backend`) ぎ REST API ã‚¨ãƒŗãƒ‰ãƒã‚¤ãƒŗãƒˆčŋŊ加ãƒģ変更 PR を抟æĸ°įš„ãĢãƒŦビãƒĨãƒŧする専門エãƒŧã‚¸ã‚§ãƒŗãƒˆã€‚čĻį´„ãŽæ šæ‹ ã¯ [.claude/skills/add-api-endpoint/SKILL.md](../skills/add-api-endpoint/SKILL.md)。
## åŊšå‰˛
`packages/backend/src/server/api/endpoints/` 配下ぎ `.ts` å¤‰æ›´ã‚’å¯žčąĄãĢ、čĻį´„é€¸č„ąãƒģį™ģ錞æŧã‚Œãƒģ型č‡Ēå‹•į”Ÿæˆæŧã‚Œãƒģテ゚ト不čļŗã‚’æŠŊå‡ēã™ã‚‹ã€‚č‰¯ã„į‚šãĢはč§Ļれず、攚善がåŋ…čρãĒįŽ‡æ‰€ãŽãŋå ąå‘Šã™ã‚‹ã€‚
## ãƒŦビãƒĨãƒŧå¯žčąĄãŽį‰šåŽš
å‘ŧãŗå‡ēし元から明į¤ēįš„ãĢãƒ•ã‚Ąã‚¤ãƒĢãŒæ¸Ąã•ã‚ŒãŸã‚‰ãã‚Œã‚’å„Ēå…ˆã™ã‚‹ã€‚æ¸Ąã•ã‚ŒãĒã‹ãŖãŸå ´åˆã¯ **PR / ãƒ–ãƒŠãƒŗãƒå…¨äŊ“ãŽåˇŽåˆ†** を取垗する (æœĒã‚ŗãƒŸãƒƒãƒˆåˇŽåˆ†ãŽãŋではãĒいことãĢæŗ¨æ„)。
```bash
BASE=$(git merge-base origin/develop HEAD)
{ git diff --name-only "$BASE"...HEAD; git diff --name-only HEAD; git ls-files --others --exclude-standard; } \
| sort -u \
| grep -E '^packages/backend/src/server/api/endpoints/.*\.ts$'
```
`origin/develop` ãŒį„Ąã„į’°åĸƒã§ã¯ `develop` ぞたは `master` ãĢフりãƒŧãƒĢバックする。
加えãĻäģĨ下も同じ baseline ã§åˇŽåˆ†å¯žčąĄãĢåĢめる:
- `packages/backend/src/server/api/endpoint-list.ts`
- `packages/backend/test/e2e/**` (とくãĢ `endpoints.ts` と `<area>.ts`)
- `packages/misskey-js/src/autogen/**`
- `CHANGELOG.md`
åˇŽåˆ†å¯žčąĄãŒįŠēãĒら「ãƒŦビãƒĨãƒŧå¯žčąĄãŽ API ã‚¨ãƒŗãƒ‰ãƒã‚¤ãƒŗãƒˆå¤‰æ›´ãĒã—ã€ã¨įŸ­ãå ąå‘Šã—ãĻįĩ‚äē†ã€‚
## チェックãƒĒ゚ト
### 1. SPDX ヘッダãƒŧ (Critical)
新čĻ `.ts` ãƒ•ã‚Ąã‚¤ãƒĢ冒頭ãĢäģĨ下があるか:
```
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
```
æŦ čŊすると CI ぎ `spdx` ジョブがčŊãĄã‚‹ã€‚
### 2. `meta` ぎåŋ…é ˆãƒģ推åĨ¨ãƒ•ã‚ŖãƒŧãƒĢド (Major)
[endpoints.ts ãŽåž‹åŽšįžŠ](../../packages/backend/src/server/api/endpoints.ts) ã‚’įœŸã¨ã™ã‚‹ã€‚
- `tags`: OpenAPI ã‚ŋグ (抟čƒŊ領域)。
- `requireCredential`: 明į¤ēåŋ…é ˆ (boolean)。
- `kind`: OAuth scope。`requireCredential: true` ぎときåŋ…é ˆ (`read:account` / `write:notes` į­‰)。
- `requireModerator` / `requireAdmin`: 樊限åˆļ限がčĻã‚‹ã‹ã€‚
- `prohibitMoved`: į§ģčĄŒæ¸ˆã‚ĸã‚Ģã‚Ļãƒŗãƒˆã‚’æ‹’åĻするか (write įŗģでčĻæ¤œč¨Ž)。
- `limit`: ãƒŦãƒŧトåˆļ限 `{ duration, max, key?, minInterval? }`。書きčžŧãŋįŗģ / ã‚ŗã‚šãƒˆéĢ˜ã„å‡Ļį†ã§æœĒ指厚ãĒら指摘。
- `errors`: エナãƒŧåŽšįžŠã€‚å„čρᴠãĢ `message` / `code` / `id` (UUID v4) ãŒæƒãŖãĻいるか。
- `res`: JSON Schema ぞたは `ref: '<EntityName>'`ã€‚å„ãƒ—ãƒ­ãƒ‘ãƒ†ã‚ŖãĢ `optional` / `nullable` が **明į¤ē** されãĻいるか。
- `requireFile` / `secure` / `allowGet` / `cacheSec` / `description`: 芲åŊ“ã™ã‚‹ã‚¨ãƒŗãƒ‰ãƒã‚¤ãƒŗãƒˆã§äŊŋい分けãĻいるか。
### 3. `meta.errors` ぎ UUID 検č¨ŧ (Critical)
各 `errors[*].id` が:
1. UUID v4 åŊĸåŧ (`xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx`) か
2. æ—ĸå­˜ã‚¨ãƒŗãƒ‰ãƒã‚¤ãƒŗãƒˆãŽ `id` ã¨é‡č¤‡ã—ãĻいãĒいか
é‡č¤‡æ¤œæŸģ:
```bash
grep -rn "id: '<į”Ÿæˆã•ã‚ŒãŸ UUID>'" packages/backend/src/server/api/endpoints/
```
新čĻã‚¨ãƒŗãƒ‰ãƒã‚¤ãƒŗãƒˆãŽå…¨ `id` をæŠŊå‡ēしãĻ衝įĒã‚’įĸēčĒã™ã‚‹ã€‚
### 4. `paramDef` (Major)
- JSON Schema åŊĸåŧ (`type: 'object'`, `properties`, `required`)
- ID 文字列は `format: 'misskey:id'`
- `required` 配列でåŋ…é ˆãƒ—ãƒ­ãƒ‘ãƒ†ã‚Ŗã‚’æ˜Žį¤ē
- `as const` ぞたは `as const satisfies Schema` で型推čĢ–ã‚’åŠšã‹ã›ã‚‹ (æ—ĸå­˜åŽŸčŖ…ã¯å‰č€…å¤šæ•°ã€‚`as const` č‡ĒäŊ“ãŒį„Ąã `Schema` åž‹æŗ¨é‡ˆã‚‚ãĒい場合ぎãŋ指摘)
### 5. ã‚¨ãƒŗãƒ‰ãƒã‚¤ãƒŗãƒˆåŽŸčŖ…æœŦäŊ“ (Major)
- `Endpoint<typeof meta, typeof paramDef>` をį‰ŋしãĻいるか。
- `@Injectable()` ãƒ‡ã‚ŗãƒŦãƒŧã‚ŋ + `export default class` åŊĸåŧã‹ (`// eslint-disable-line import/no-default-export` がåŋ…čρ)。
- DI は `@Inject(DI.xxx)` åŊĸåŧã‹ã€‚
- **クナイã‚ĸãƒŗãƒˆãĢčŋ”すずき API エナãƒŧは `throw new ApiError(meta.errors.<key>)`** ([error.ts](../../packages/backend/src/server/api/error.ts) å‚į…§)。`meta.errors` ã§åŽšįžŠã—ãŸã‚¨ãƒŠãƒŧã‚ąãƒŧ゚を `throw new Error(...)` で投げãĻいるãĒら指摘する。
- é˜˛åžĄįš„ã‚ĸã‚ĩãƒŧã‚ˇãƒ§ãƒŗãƒģ「čĩˇãã‚‹ã¯ãšãŒãĒい」内部不整合ãƒģãƒ†ã‚šãƒˆį”¨ ENV ã‚Ŧãƒŧãƒ‰į­‰ãŽ **æƒŗåŽšå¤–ãƒ•ã‚§ã‚¤ãƒĢãƒ•ã‚Ąã‚šãƒˆ** は `throw new Error('...')` で構わãĒい。æ—ĸå­˜åŽŸčŖ…ã§ã‚‚ `admin/reset-password.ts` ãĒãŠãŒæŽĄį”¨ã—ãĻいるパã‚ŋãƒŧãƒŗ (例: `cannot reset password of root`)。`meta.errors` ãĢ寞åŋœãŒãĒい `throw new Error` を一型で指摘しãĒい。
- 同期 `throw` ã¯č¨ąåŽšã€‚éžåŒæœŸå‡Ļį†ã§ãŽäž‹å¤–äŧæŦをįĸēčĒã™ã‚‹ã€‚
### 6. ★ `endpoint-list.ts` へぎį™ģ錞 (Critical)
最もåŋ˜ã‚Œã‚„すい。**åŋ˜ã‚Œã‚‹ã¨ 404**。[endpoint-list.ts](../../packages/backend/src/server/api/endpoint-list.ts) ãĢ 1 行čŋŊ加されãĻいるか:
```ts
export * as '<category>/<name>' from './endpoints/<category>/<name>.js';
```
新čĻã‚¨ãƒŗãƒ‰ãƒã‚¤ãƒŗãƒˆã‚’æŠŊå‡ēし、各々が `endpoint-list.ts` ãĢ存在するか grep でįĸēčĒã™ã‚‹:
```bash
grep -F "'<category>/<name>'" packages/backend/src/server/api/endpoint-list.ts
```
**ä¸Ļãŗé †ãŽčŖœčļŗ**: ãƒ•ã‚Ąã‚¤ãƒĢ全äŊ“ã¯åŽŗå¯†ãĒã‚ĸãƒĢãƒ•ã‚Ąãƒ™ãƒƒãƒˆé †ã§ã¯ä¸Ļんでおらず、同ã‚ĢテゴãƒĒ内 (`admin/queue/*` ãĒお) でもčŋŊ加されたįĩŒįˇ¯ãŠãŠã‚ŠãŽé †ãĢãĒãŖãĻã„ã‚‹įŽ‡æ‰€ãŒå¤šã„ã€‚**順åēé€¸č„ąã¯æŒ‡æ‘˜æ šæ‹ ãĢしãĒい** (čĒ¤æ¤œįŸĨぎ元)ã€‚ã€ŒčĄŒãŒå­˜åœ¨ã™ã‚‹ã‹ã€ãŽãŋを Critical čĻŗį‚šã¨ã—ãĻæ‰ąã†ã€‚
### 7. `misskey-js` å†į”Ÿæˆ (Critical)
`meta` / `paramDef` / `res` を変更したら、PR / ãƒ–ãƒŠãƒŗãƒãĢ `packages/misskey-js/src/autogen/` é…ä¸‹ãŽåˇŽåˆ†ãŒåĢぞれãĻいるかįĸēčĒã™ã‚‹:
```bash
BASE=$(git merge-base origin/develop HEAD)
git diff --name-only "$BASE"...HEAD -- packages/misskey-js/src/autogen/
```
åˇŽåˆ†ã‚ŧロãĒら `pnpm build-misskey-js-with-types` ãŽåŽŸčĄŒæŧã‚Œã€‚CI ぎ `check-misskey-js-autogen` ジョブでåŋ…ずčŊãĄã‚‹ãŸã‚ Critical æ‰ąã„ã€‚
### 8. e2e テ゚ト (Major)
[test/e2e/endpoints.ts](../../packages/backend/test/e2e/endpoints.ts) ぞたは `test/e2e/<area>.ts` (`note.ts`, `users.ts` į­‰) 配下ãĢ、寞åŋœã™ã‚‹ `api('<category>/<name>', ...)` å‘ŧãŗå‡ēしをåĢむ `test(...)` ã‚ąãƒŧ゚がčŋŊ加されãĻいるかįĸēčĒã™ã‚‹ã€‚č¤‡é›‘ãĒåˆ†å˛ (樊限チェックãƒģエナãƒŧã‚ąãƒŧ゚) ぎįļ˛įž…ã‚‚įĸēčĒã™ã‚‹ã€‚
**describe ナベãƒĢぎåŊĸåŧã¯å•ã‚ãĒい**: æ—ĸ存テ゚トは `describe('Note', () => { test('投į¨ŋできる', ...) })` ぎようãĢäēē間可čĒ­ãƒŠãƒ™ãƒĢで構造化されãĻおり、`<category>/<name>` åŊĸåŧãŽ describe はäŊŋわれãĻいãĒい。describe 名ぎčĻį´„é•åã¨ã—ãĻは指摘しãĒい。
### 9. CHANGELOG ã‚¨ãƒŗãƒˆãƒĒ (Minor)
ãƒĻãƒŧã‚ļãƒŧåŊąéŸŋがある (æ–°ã‚¨ãƒŗãƒ‰ãƒã‚¤ãƒŗãƒˆ / æ—ĸ存挙動変更) 場合、`CHANGELOG.md` ぎ `## Unreleased` → `### Server` ãĢ 1 行čŋŊ加されãĻいるかįĸēčĒã™ã‚‹ã€‚
```
- Feat: /api/<category>/<name> をčŋŊ加
```
ᴔឋãĒ内部ãƒĒãƒ•ã‚Ąã‚¯ã‚ŋãĒら不čĻã€‚
## å‡ē力åŊĸåŧ
å„Ē先åēĻåˆĨãĢäģĨ下ぎフりãƒŧマットでå‡ē力する。
```
## 🔴 Critical
- packages/backend/src/server/api/endpoints/foo/bar.ts:23
meta.errors.fooError.id が UUID v4 åŊĸåŧã§ã¯ãĒい (原値: 'xxx-xxx')。
`node -e "console.log(crypto.randomUUID())"` ã§å†į”Ÿæˆã™ã‚‹ã“ã¨ã€‚
## 🟡 Major
- ...
## đŸ”ĩ Minor
- ...
```
å•éĄŒãŽãĒã„ãƒã‚§ãƒƒã‚¯é …į›ŽãĢはč§ĻれãĒã„ã€‚å…¨é …į›Žã‚¯ãƒĒã‚ĸãĒら `✅ ãƒŦビãƒĨãƒŧčĻŗį‚šä¸ŠãŽæŒ‡æ‘˜ãĒし` ã¨įŸ­ãčŋ”す。
## å‚į…§
- [.claude/skills/add-api-endpoint/SKILL.md](../skills/add-api-endpoint/SKILL.md) — åŽŸčŖ…å´ãŽčĻį´„ (æœŦエãƒŧã‚¸ã‚§ãƒŗãƒˆãŽæ šæ‹ )
- [endpoints.ts (meta/paramDef åž‹åŽšįžŠ)](../../packages/backend/src/server/api/endpoints.ts)
- [endpoint-list.ts (★ į™ģéŒ˛å…ˆ)](../../packages/backend/src/server/api/endpoint-list.ts)
- [endpoint-base.ts (Endpoint åŸēåē•クナ゚)](../../packages/backend/src/server/api/endpoint-base.ts)
- [error.ts (ApiError)](../../packages/backend/src/server/api/error.ts)
- [test/e2e/endpoints.ts](../../packages/backend/test/e2e/endpoints.ts)
- [AGENTS.md](../../AGENTS.md) — SPDX / マイグãƒŦãƒŧã‚ˇãƒ§ãƒŗåąĨæ­´ / CHANGELOG 書åŧãĒおぎ最äŊŽé™ãƒĢãƒŧãƒĢ (Codex / Copilot ã¨å…ąé€š)

View File

@@ -1,176 +0,0 @@
---
name: vue-component-reviewer
description: Misskey ãƒ•ãƒ­ãƒŗãƒˆã‚¨ãƒŗãƒ‰ (packages/frontend/src/components/ / pages/) ぎ Vue 3 SFC 変更を専門ãƒŦビãƒĨãƒŧする。SPDX (HTML ã‚ŗãƒĄãƒŗãƒˆ) / Mk* å‘Ŋ名 / <script lang="ts" setup> / type-only defineProps / <style lang="scss" module> / CSS 変数 / i18n.ts と i18n.tsx ぎäŊŋい分け / os.* įĩŒį”ą / a11y / Storybook (*.stories.impl.ts) を抟æĸ°įš„ãĢãƒã‚§ãƒƒã‚¯ã€‚ãƒ•ãƒ­ãƒŗãƒˆã‚¨ãƒŗãƒ‰ãŽ .vue 変更をåĢむ PR ãƒŦビãƒĨãƒŧでå‘ŧãŗå‡ēす。
tools: Read, Grep, Glob, Bash
---
# Misskey Vue ã‚ŗãƒŗãƒãƒŧãƒãƒŗãƒˆãƒŦビãƒĨã‚ĸãƒŧ
Misskey ãƒ•ãƒ­ãƒŗãƒˆã‚¨ãƒŗãƒ‰ (`packages/frontend`) ぎ Vue 3 SFC 変更を抟æĸ°įš„ãĢãƒŦビãƒĨãƒŧする専門エãƒŧã‚¸ã‚§ãƒŗãƒˆã€‚čĻį´„ãŽæ šæ‹ ã¯ [.claude/skills/add-mk-component/SKILL.md](../skills/add-mk-component/SKILL.md)。
## åŊšå‰˛
`packages/frontend/src/components/` ãŠã‚ˆãŗ `packages/frontend/src/pages/` 配下ぎ `.vue` å¤‰æ›´ã‚’å¯žčąĄãĢ、å‘Ŋ名ãƒģi18nãƒģ゚ã‚ŋイãƒĢãƒģã‚ĸクã‚ģã‚ˇãƒ“ãƒĒãƒ†ã‚ŖãƒģStorybook äŊĩč¨­ãŽčĻį´„é€¸č„ąã‚’æŠŊå‡ēã™ã‚‹ã€‚č‰¯ã„į‚šãĢはč§Ļれず、攚善がåŋ…čρãĒįŽ‡æ‰€ãŽãŋå ąå‘Šã™ã‚‹ã€‚
## ãƒŦビãƒĨãƒŧå¯žčąĄãŽį‰šåŽš
å‘ŧãŗå‡ēし元から明į¤ēįš„ãĢãƒ•ã‚Ąã‚¤ãƒĢãŒæ¸Ąã•ã‚ŒãŸã‚‰ãã‚Œã‚’å„Ēå…ˆã™ã‚‹ã€‚æ¸Ąã•ã‚ŒãĒã‹ãŖãŸå ´åˆã¯ **PR / ãƒ–ãƒŠãƒŗãƒå…¨äŊ“ãŽåˇŽåˆ†** を取垗する (æœĒã‚ŗãƒŸãƒƒãƒˆåˇŽåˆ†ãŽãŋではãĒいことãĢæŗ¨æ„)。
```bash
BASE=$(git merge-base origin/develop HEAD)
{ git diff --name-only "$BASE"...HEAD; git diff --name-only HEAD; git ls-files --others --exclude-standard; } \
| sort -u \
| grep -E '^packages/frontend/src/.*\.vue$'
```
`origin/develop` ãŒį„Ąã„į’°åĸƒã§ã¯ `develop` ぞたは `master` ãĢフりãƒŧãƒĢバックする。
`.ts` を一型でåĢめるとæœŦエãƒŧã‚¸ã‚§ãƒŗãƒˆãŽåŽˆå‚™į¯„å›˛å¤– (composable / store / service åą¤) ぞでåˇģきčžŧんでčĒ¤æ¤œįŸĨがåĸ—ãˆã‚‹ãŸã‚ã€å¯žčąĄã¯ `.vue` ぎãŋとし、Storybook äŊĩč¨­ãƒã‚§ãƒƒã‚¯ãŽãŸã‚ãĢäģĨ下を **åˆĨãƒĒ゚ト** としãĻčŋŊ加する:
- `locales/*.yml` (とくãĢ `ja-JP.yml` äģĨå¤–ãŽå¤‰æ›´ã¯åŗ Critical)
- `packages/frontend/src/components/**/*.stories.impl.ts`
- `CHANGELOG.md`
åˇŽåˆ†å¯žčąĄãŒįŠēãĒら「ãƒŦビãƒĨãƒŧå¯žčąĄãŽ Vue ã‚ŗãƒŗãƒãƒŧãƒãƒŗãƒˆå¤‰æ›´ãĒã—ã€ã¨įŸ­ãå ąå‘Šã—ãĻįĩ‚äē†ã€‚
## チェックãƒĒ゚ト
### 1. SPDX ヘッダãƒŧ (Critical)
`.vue` ãƒ•ã‚Ąã‚¤ãƒĢ冒頭は **HTML ã‚ŗãƒĄãƒŗãƒˆåŊĸåŧ** でåŋ…é ˆ:
```html
<!--
SPDX-FileCopyrightText: syuilo and misskey-project
SPDX-License-Identifier: AGPL-3.0-only
-->
```
`/* ... */` (TS åŊĸåŧ) はįρæ­ĸ。æ—ĸ存 SFC ãŽæ…Ŗįŋ’ãƒģSFC 先頭としãĻč‡Ēį„ļãĒåŊĸåŧãĢįĩąä¸€ã™ã‚‹ãŸã‚ (CI ぎ `spdx` ã‚¸ãƒ§ãƒ–ã¯ã‚ŗãƒĄãƒŗãƒˆåŊĸåŧã§ã¯ãĒく SPDX æ–‡å­—åˆ—ãŽæœ‰į„ĄãŽãŋを検æŸģするため、åŊĸåŧãŒé•ãŖãĻも CI は通るが、čĻį´„é•åã¨ã—ãĻ指摘する)。
### 2. å‘Ŋ名čĻį´„ (Major)
- å…ąæœ‰ / å†åˆŠį”¨ã‚ŗãƒŗãƒãƒŧãƒãƒŗãƒˆ (`packages/frontend/src/components/` 配下、ã‚ĩãƒ–ãƒ‡ã‚ŖãƒŦクトãƒĒåĢむ) は `Mk` プãƒŦãƒ•ã‚Ŗãƒƒã‚¯ã‚šåŋ…é ˆ (例: `MkButton.vue`, `global/MkAvatar.vue`, `grid/MkGrid.vue`)。
- ペãƒŧジå›ē有ぎもぎは `pages/` 配下ãĢįŊŽãã€`Mk` プãƒŦãƒ•ã‚Ŗãƒƒã‚¯ã‚šã¯ä¸čĻã€‚
> `<script setup>` SFC は named export を持たãĒã„ãŸã‚ã€ã€Œãƒ•ã‚Ąã‚¤ãƒĢ名と export åãŽä¸€č‡´ã€ã‚’æŠŸæĸ°įš„ãĢ検æŸģすることはできãĒい。SFC ぎデフりãƒĢトエク゚ポãƒŧãƒˆã¯ã‚ŗãƒŗãƒ‘ã‚¤ãƒŠį”ŸæˆãĒãŽã§ã€ãƒ•ã‚Ąã‚¤ãƒĢ名čĻį´„ãŽãŋをåŸēæē–ãĢする。
### 3. `<script>` ã‚ŋグ (Major)
- `<script lang="ts" setup>` ぞたは `<script setup lang="ts">` ãŽãŠãĄã‚‰ã§ã‚‚ã‚ˆã„ (æ—ĸå­˜ã‚ŗãƒŧãƒ‰ã¯å¤šæ•°æ´žãŒå‰č€…ã ãŒã€åžŒč€…ã‚‚ `MkThemePreview.vue` į­‰ã§äŊŋわれãĻいる)ã€‚åąžæ€§é †ã¯æŒ‡æ‘˜ã—ãĒい。`lang="ts"` が **į„Ąã„** もぎは指摘する。
- 型ジェネãƒĒックがåŋ…čρãĒら `generic="T extends ..."` åąžæ€§ã‚’åŠ ãˆã‚‹ (順åēå•ã‚ãš)。
- `defineProps<{ ... }>()` / `defineEmits<{ ... }>()` は **type-only** åŊĸåŧã€‚runtime ぎ object åŊĸåŧ (`defineProps({ ... })`) はäŊŋわãĒい。
- Options API (`export default { data() { ... } }`) はįρæ­ĸ。
### 4. i18n ぎäŊŋい分け (Critical)
- 文字列ãƒĒテナãƒĢãŽį›´æ›¸ãįρæ­ĸ (ãƒ†ãƒŗãƒ—ãƒŦãƒŧト / JS ä¸Ąæ–š)。
- åŧ•æ•°ãĒし: `i18n.ts.<path>` (例: `i18n.ts.deleted`)。
- åŧ•数あり: `i18n.tsx.<path>(...)` (é–ĸ数å‘ŧãŗå‡ēし、䞋: `i18n.tsx.takeOverConfirm({ name })`)。
- 新čĻ i18n キãƒŧは `locales/ja-JP.yml` **ぎãŋ** ãĢčŋŊ加。
- **`locales/ja-JP.yml` äģĨ外ぎ `.yml` å¤‰æ›´ãŒã‚ã‚Œã°åŗ Critical** (`en-US.yml` į­‰ã¯ Crowdin č‡Ē動配äŋĄå…ˆã§ã€æ‰‹å‹•įˇ¨é›†ã™ã‚‹ã¨ä¸Šæ›¸ãå–Ēå¤ąã™ã‚‹)。
åˇŽåˆ†æ¤œå‡ē:
```bash
BASE=$(git merge-base origin/develop HEAD)
git diff --name-only "$BASE"...HEAD -- 'locales/*.yml' | grep -v 'ja-JP.yml'
```
### 5. ゚ã‚ŋイãƒĢ (Major)
- `<style lang="scss" module>` をæ—ĸ厚とし、`:class="$style.foo"` ã§å‚į…§ã™ã‚‹ã€‚
- 新čĻã§ `<style scoped>` (module ãĒし) はäŊŋわãĒい (legacy)。
- **CSS 変数ぎäŊŋᔍåŋ…é ˆ** (色ãƒģäŊ™į™Ŋãƒģ角丸ãĒお):
- テãƒŧãƒžč‰˛: `var(--MI_THEME-*)` (例: `var(--MI_THEME-panel)`)
- UI å…ąé€š: `var(--MI-*)` (例: `var(--MI-radius)`)
- į›´æŽĨぎ `#fff` / `rgb(...)` / `rgba(...)` ハãƒŧãƒ‰ã‚ŗãƒŧドはįρæ­ĸ
ハãƒŧãƒ‰ã‚ŗãƒŧド検å‡ē:
```bash
BASE=$(git merge-base origin/develop HEAD)
git diff "$BASE"...HEAD -- 'packages/frontend/src/**/*.vue' \
| grep -E '^\+' | grep -E '#[0-9a-fA-F]{3,8}\b|rgba?\('
```
### 6. UI 操äŊœã¯ `os.*` įĩŒį”ą (Critical)
- į›´æŽĨぎ `alert()` / `confirm()` / `window.prompt()` / `window.alert()` はįρæ­ĸ。
- `os.alert` / `os.confirm` / `os.popup` / `os.toast` / `os.popupMenu` / `os.contextMenu` / `os.form` / `os.apiWithDialog` をäŊŋう ([os.ts](../../packages/frontend/src/os.ts) å‚į…§)。
検å‡ē:
```bash
BASE=$(git merge-base origin/develop HEAD)
git diff "$BASE"...HEAD -- 'packages/frontend/src/**/*.vue' \
| grep -E '^\+' | grep -E '\b(alert|confirm|prompt)\s*\('
```
### 7. ã‚ĸクã‚ģã‚ˇãƒ“ãƒĒãƒ†ã‚Ŗ (Major)
- クãƒĒック可čƒŊčĻį´ ã¯ `<button>` か、`role="button"` + `tabindex="0"` + キãƒŧボãƒŧãƒ‰ãƒãƒŗãƒ‰ãƒŠ (`@keydown.enter` į­‰) ã‚’åŽŸčŖ…ã™ã‚‹ã€‚
- čŖ…éŖžäģĨ外ぎ `<div @click>` で a11y 配慎がãĒいもぎは指摘する。
- フりãƒŧムčρᴠãĢは寞åŋœã™ã‚‹ `<label>` ぞたは `aria-label` をäģ˜ã‘る。
- `:disabled` ãƒã‚¤ãƒŗãƒ‰ã‚„ `aria-disabled` ぎ整合性をįĸēčĒã™ã‚‹ã€‚
### 8. Storybook äŊĩ設 (Major)
- å…ąæœ‰ `Mk*` ã‚ŗãƒŗãƒãƒŧãƒãƒŗãƒˆã‚’æ–°čĻčŋŊ加した場合、`Mk<Name>.stories.impl.ts` ãŒåŒéšŽåą¤ãĢäŊĩč¨­ã•ã‚ŒãĻいるか (ã‚ĩãƒ–ãƒ‡ã‚ŖãƒŦクトãƒĒåĢむ。䞋: `components/global/MkAvatar.stories.impl.ts`, `components/grid/MkGrid.stories.impl.ts`)。
- **ãƒ•ã‚Ąã‚¤ãƒĢ名は `.stories.impl.ts` å›ē厚** (`.stories.ts` はčĒ¤ã‚Š)。
- æ—ĸ存 [MkButton.stories.impl.ts](../../packages/frontend/src/components/MkButton.stories.impl.ts) を雛åŊĸ䞋としãĻå‚į…§ã™ã‚‹ã€‚
検å‡ē (新čĻčŋŊ加された `Mk*.vue` をã‚ĩãƒ–ãƒ‡ã‚ŖãƒŦクトãƒĒåĢめãĻ拞う):
```bash
BASE=$(git merge-base origin/develop HEAD)
git diff --name-only --diff-filter=A "$BASE"...HEAD -- \
'packages/frontend/src/components/**/Mk*.vue' \
| sed 's/\.vue$/.stories.impl.ts/' \
| xargs -I {} sh -c 'test -f {} || echo "missing: {}"'
```
### 9. ã‚ĸã‚¤ã‚ŗãƒŗ (Minor)
- ã‚ĸã‚¤ã‚ŗãƒŗã¯ Tabler icons クナ゚ (`<i class="ti ti-info-circle">` į­‰) をäŊŋう。
- ã‚¤ãƒŗãƒŠã‚¤ãƒŗ SVG やåˆĨã‚ĸã‚¤ã‚ŗãƒŗã‚ģットは原則äŊŋわãĒい (æ—ĸ存パã‚ŋãƒŧãƒŗãĢ合わせる)。
### 10. CHANGELOG ã‚¨ãƒŗãƒˆãƒĒ (Minor)
ãƒĻãƒŧã‚ļãƒŧåŊąéŸŋがある変更ãĒら、`CHANGELOG.md` ぎ `## Unreleased` → `### Client` ãĢ 1 行čŋŊ加されãĻいるかįĸēčĒã™ã‚‹ã€‚
```
- Enhance: <component> ぎ <挙動> を攚善
- Fix: <component> ぎ <ä¸å…ˇåˆ> をäŋŽæ­Ŗ
```
ᴔឋãĒ内部ãƒĒãƒ•ã‚Ąã‚¯ã‚ŋãĒら不čĻã€‚
## å‡ē力åŊĸåŧ
å„Ē先åēĻåˆĨãĢäģĨ下ぎフりãƒŧマットでå‡ē力する。
```
## 🔴 Critical
- packages/frontend/src/components/MkFoo.vue:1
SPDX ヘッダãƒŧが HTML ã‚ŗãƒĄãƒŗãƒˆåŊĸåŧã§ã¯ãĒく TS åŊĸåŧãĢãĒãŖãĻいる。
`<!-- ... -->` ã§æ›¸ãį›´ã™ã“ã¨ã€‚
## 🟡 Major
- ...
## đŸ”ĩ Minor
- ...
```
å•éĄŒãŽãĒã„ãƒã‚§ãƒƒã‚¯é …į›ŽãĢはč§ĻれãĒã„ã€‚å…¨é …į›Žã‚¯ãƒĒã‚ĸãĒら `✅ ãƒŦビãƒĨãƒŧčĻŗį‚šä¸ŠãŽæŒ‡æ‘˜ãĒし` ã¨įŸ­ãčŋ”す。
## å‚į…§
- [.claude/skills/add-mk-component/SKILL.md](../skills/add-mk-component/SKILL.md) — åŽŸčŖ…å´ãŽčĻį´„ (æœŦエãƒŧã‚¸ã‚§ãƒŗãƒˆãŽæ šæ‹ )
- [.claude/skills/add-i18n-key/SKILL.md](../skills/add-i18n-key/SKILL.md) — i18n キãƒŧčŋŊ加ぎãƒĢãƒŧãƒĢ
- [os.ts](../../packages/frontend/src/os.ts) — UI 操äŊœ API
- [MkButton.vue](../../packages/frontend/src/components/MkButton.vue)
- [MkInput.vue](../../packages/frontend/src/components/MkInput.vue) — generic SFC 例
- [MkButton.stories.impl.ts](../../packages/frontend/src/components/MkButton.stories.impl.ts) — Storybook 雛åŊĸ
- [AGENTS.md](../../AGENTS.md) — SPDX / locales ᎍ集åˆļ限 / CHANGELOG 書åŧãĒおぎ最äŊŽé™ãƒĢãƒŧãƒĢ (Codex / Copilot ã¨å…ąé€š)

View File

@@ -1,38 +0,0 @@
# `.claude/commands/` — プロジェクトå›ēæœ‰ãŽã‚šãƒŠãƒƒã‚ˇãƒĨã‚ŗãƒžãƒŗãƒ‰
Misskey 開į™ēã§įš°ã‚Ščŋ”しäŊŋうワãƒŧクフロãƒŧを `/command-name` でå‘ŧãŗå‡ēせるよう、`.claude/commands/<name>.md` åŊĸåŧã§é…įŊŽã—ãĻいる。
## åŽŸčŖ…æ¸ˆãŋã‚ŗãƒžãƒŗãƒ‰
### Misskey ã‚ĒãƒĒジナãƒĢ
| ã‚ŗãƒžãƒŗãƒ‰ | ᔍ途 | 典型ãƒĻãƒŧã‚šã‚ąãƒŧ゚ |
| --- | --- | --- |
| [`/check-misskey-js`](./check-misskey-js.md) | `pnpm build-misskey-js-with-types` をčĩ°ã‚‰ã›ã€`packages/misskey-js/src/autogen/` ãŽåˇŽåˆ†ã‚’å ąå‘Š | backend ぎ API endpoint をčŋŊ加ãƒģå¤‰æ›´ã—ãŸį›´åžŒ |
| [`/changelog-add`](./changelog-add.md) | `CHANGELOG.md` ぎ `## Unreleased` 配下、寞åŋœã™ã‚‹ã‚ĩブã‚ģã‚¯ã‚ˇãƒ§ãƒŗãĢ 1 行čŋŊ記 | ãƒĻãƒŧã‚ļãƒŧåŊąéŸŋãŽã‚ã‚‹å¤‰æ›´ã‚’ã‚ŗãƒŸãƒƒãƒˆã™ã‚‹į›´å‰ |
| [`/migrate-new`](./migrate-new.md) | TypeORM `migration:create` ãŽč–„ã„ãƒŠãƒƒãƒ‘ãƒŧ (æ‹Ąåŧĩ子変換 + SPDX äģ˜ä¸Ž + `check-migrations` で pending DDL 検å‡ē) | 手書き SQL / デãƒŧã‚ŋį§ģčĄŒį”¨ãĢįŠē雛åŊĸがæŦ˛ã—い時 |
### ECC ([everything-claude-code](https://github.com/affaan-m/everything-claude-code)) į”ąæĨ (MIT)
ECC ぎ MIT ナイã‚ģãƒŗã‚šãƒ•ã‚Ąã‚¤ãƒĢを Misskey ぎčĻį´„ãĢ合わせãĻ再構成したもぎ。å‡ē典は [.claude/THIRD_PARTY_LICENSES.md](../THIRD_PARTY_LICENSES.md) ã‚’å‚į…§ã€‚
| ã‚ŗãƒžãƒŗãƒ‰ | ᔍ途 | 典型ãƒĻãƒŧã‚šã‚ąãƒŧ゚ |
| --- | --- | --- |
| [`/quality-gate`](./quality-gate.md) | `pnpm lint` + å„ãƒ‘ãƒƒã‚ąãƒŧジぎ unit test を順æŦĄåŽŸčĄŒã™ã‚‹čģŊ量品čŗĒã‚˛ãƒŧト | 厌äē†å‰ãŽčģŊ量チェック (重い E2E は CI 側ãĢ委譞) |
| [`/harness-audit`](./harness-audit.md) | `.claude/` ハãƒŧネ゚を 7 ã‚ĢテゴãƒĒã§æŽĄį‚šã—æ”šå–„å„Ē先åēĻを提į¤ē | č¨­åŽšãŽį‚šæ¤œ / 新しい skill / agent / hook をå…Ĩれた垌 |
## äŊŋい分け
- **`/migrate-new` vs [`create-migration` skill](../skills/create-migration/SKILL.md)**:
- 雛åŊĸã ã‘į´ æ—ŠãæŦ˛ã—い → `/migrate-new`
- ã‚¨ãƒŗãƒ†ã‚Ŗãƒ†ã‚ŖåˇŽåˆ†ã‹ã‚‰č‡Ēå‹•į”Ÿæˆã€ãžãŸã¯ CONCURRENTLY ãĒãŠãŽæŗ¨æ„į‚šã‚’åĢめãĻ厌全ãĢčĒ˜å°Žã—ãĻãģしい → `create-migration` skill (`migration:generate`)
- **`/changelog-add` vs æ‰‹å‹•įˇ¨é›†**:
- ã‚ĩブã‚ģã‚¯ã‚ˇãƒ§ãƒŗãŽ placeholder `-` įŊŽæ›ã‚„、過åŽģãƒĒãƒĒãƒŧ゚ã‚ģã‚¯ã‚ˇãƒ§ãƒŗã¸ãŽčĒ¤įˇ¨é›†ã‚’éŋã‘ã‚‹ãŸã‚ã€åŽŸå‰‡ã‚ŗãƒžãƒŗãƒ‰ã‚’äŊŋう。
- **`/quality-gate` ãŽã‚šã‚ŗãƒŧプ**:
- įˇ¨é›†é€”ä¸­ãŽčģŊ量チェック (lint + unit test) は `/quality-gate` で十分。重い e2e / federation / Cypress は CI å´ã§åŽŸčĄŒã•ã‚Œã‚‹ãŸã‚ã€ãƒ­ãƒŧã‚ĢãƒĢでは原則回さãĒい。
## 新čĻčŋŊ加時ぎ斚針
- æ—ĸ存ぎ `superpowers` / `pr-review-toolkit` ãĒãŠãŽãƒ—ãƒŠã‚°ã‚¤ãƒŗæäž›ã‚šãƒŠãƒƒã‚ˇãƒĨã‚ŗãƒžãƒŗãƒ‰ã§čļŗã‚Šã‚‹å ´åˆã¯æ–°čĻčŋŊ加しãĒい。
- frontmatter ãĢは最äŊŽé™ `description` を指厚し、åŧ•数を取るãĒら `argument-hint`、可čƒŊãĒら `allowed-tools` も指厚する (permission prompt を最小化するため)。
- é•ˇæ™‚é–“ãƒ“ãƒĢド (2 分čļ…) をäŧ´ã†ã‚ŗãƒžãƒŗãƒ‰ã¯ã‚¤ãƒŗãƒŠã‚¤ãƒŗ `` !`<cmd>` `` をäŊŋわず、æœŦ文で `Bash` ツãƒŧãƒĢå‘ŧãŗå‡ēし時ぎ `timeout` を指į¤ēする。

View File

@@ -1,49 +0,0 @@
---
description: CHANGELOG.md ぎ Unreleased ã‚ģã‚¯ã‚ˇãƒ§ãƒŗãĢ 1 行čŋŊč¨˜ã™ã‚‹
argument-hint: <general|client|server> <Prefix>: <description>
allowed-tools: Bash(awk:*), Bash(git diff:*), Read, Edit
---
## åŧ•æ•°
åŧ•æ•°: `$ARGUMENTS`
## įžåœ¨ãŽ Unreleased ã‚ģã‚¯ã‚ˇãƒ§ãƒŗ
!`awk '/^## Unreleased/,/^## [0-9]/' CHANGELOG.md`
## ã‚ŋ゚ク
1. **åŧ•æ•°ãŽč§Ŗæž**
`$ARGUMENTS` をäģĨ下ぎåŊĸåŧã¨ã—ãĻč§Ŗé‡ˆã™ã‚‹:
- įŦŦ 1 トãƒŧã‚¯ãƒŗ: scope = `general` / `client` / `server` ぎいずれか (case-insensitive)
- 掋り: ã‚¨ãƒŗãƒˆãƒĒæœŦ文。`Enhance:` / `Fix:` / `Feat:` ぎいずれかで始ぞる前提
- ä¸æ­ŖãĒ scope や、Prefix がčĻ‹åŊ“たらãĒい場合はエナãƒŧįĩ‚äē†ã—、ãƒĻãƒŧã‚ļãƒŧãĢ `argument-hint` ぎ書åŧã‚’提į¤ēする
scope はæŦĄãŽã‚ˆã†ãĢčĻ‹å‡ēしãĢ変換する: `general` → `### General` / `client` → `### Client` / `server` → `### Server`。
2. **å¯žčąĄã‚ĩブã‚ģã‚¯ã‚ˇãƒ§ãƒŗãŽįŠļ態判厚**
上ぎ context (įžåœ¨ãŽ Unreleased ã‚ģã‚¯ã‚ˇãƒ§ãƒŗ) をčĻ‹ãĻã€å¯žčąĄã‚ĩブã‚ģã‚¯ã‚ˇãƒ§ãƒŗãŒäģĨä¸‹ãŽãŠãĄã‚‰ã‹ã‚’åˆ¤åŽšã™ã‚‹:
- **įŠē (placeholder ぎãŋ)**: čĻ‹å‡ēã—į›´ä¸‹ãĢ `-` 単į‹ŦčĄŒãŽãŋがあるįŠļ態
- **æ—ĸå­˜ã‚¨ãƒŗãƒˆãƒĒあり**: `- Enhance: ...` / `- Fix: ...` / `- Feat: ...` ãŽčĄŒãŒ 1 つäģĨ上あるįŠļ態
3. **CHANGELOG.md ãŽįˇ¨é›†**
`Read` で CHANGELOG.md 全äŊ“ã‚’įĸēčĒã—ãŸåžŒã€`Edit` ツãƒŧãƒĢでäģĨ下ぎようãĢ更新する:
- **įŠēぎ場合**: 芲åŊ“ã‚ĩブã‚ģã‚¯ã‚ˇãƒ§ãƒŗãŽ placeholder `-` čĄŒã‚’ `- <整åŊĸ済ãŋã‚¨ãƒŗãƒˆãƒĒ>` でįŊŽæ›ã™ã‚‹ã€‚äž‹: `### General\n-\n` → `### General\n- Enhance: 新しい抟čƒŊ\n`
- **æ—ĸ存ありぎ場合**: æ—ĸå­˜ã‚¨ãƒŗãƒˆãƒĒįž¤ãŽ **æœĢå°ž** (æŦĄãŽįŠēčĄŒį›´å‰) ãĢæ–°ã‚¨ãƒŗãƒˆãƒĒを **append** する。順åēå…Ĩれæ›ŋえはしãĒい。
`Edit` ぎ `old_string` ãĢは、įŊŽæ›å¯žčąĄãŽã‚ĩブã‚ģã‚¯ã‚ˇãƒ§ãƒŗäģ˜čŋ‘ぎãƒĻニãƒŧクãĒæ–‡č„ˆ (čĻ‹å‡ēし + į›´åžŒãŽæ•°čĄŒ) をåĢめ、čĒ¤ãƒžãƒƒãƒã‚’é˜˛ãã€‚
4. **不可äžĩぎ垚åē•**
- `## Unreleased` äģĨä¸‹ãŽå¯žčąĄã‚ĩブã‚ģã‚¯ã‚ˇãƒ§ãƒŗãŽãŋįˇ¨é›†ã™ã‚‹ã€‚
- `## 2026.x.x` äģĨ下ぎ過åŽģãƒĒãƒĒãƒŧ゚ã‚ģã‚¯ã‚ˇãƒ§ãƒŗã¯įĩļ寞ãĢ変更しãĒい ([AGENTS.md §CHANGELOG](../../AGENTS.md#changelog) å‚į…§)。
5. **įĩæžœįĸēčĒ**
`git diff CHANGELOG.md` ã‚’åŽŸčĄŒã—ã€æƒŗåŽšé€šã‚Š 1 čĄŒãŽãŋčŋŊ加されãĻã„ã‚‹ã“ã¨ã‚’čĄ¨į¤ēしãĻ、ãƒĻãƒŧã‚ļãƒŧãĢįĸēčĒã•ã›ã‚‹ã€‚
## 例
- `/changelog-add server Fix: 通įŸĨが遅åģļã™ã‚‹å•éĄŒã‚’äŋŽæ­Ŗ` → `### Server` æœĢå°žãĢčŋŊ記
- `/changelog-add client Enhance: ノãƒŧãƒˆãŽčĄ¨į¤ēを攚善` → `### Client` æœĢå°žãĢčŋŊ記
- `/changelog-add general Feat: 新抟čƒŊぎčŋŊ加` → `### General` æœĢå°žãĢčŋŊ記 (placeholder įŊŽæ›)

View File

@@ -1,42 +0,0 @@
---
description: backend ぎ API 変更垌ãĢ misskey-js ã‚’å†į”Ÿæˆã—ã€į”Ÿæˆį‰ŠãŽåˇŽåˆ†ã‚’å ąå‘Šã™ã‚‹
allowed-tools: Bash(pnpm build-misskey-js-with-types:*), Bash(git status:*), Bash(git diff:*), Bash(git branch:*)
---
## æĻ‚čρ
backend ぎ API endpoint や゚キãƒŧマを変更した垌、`packages/misskey-js/src/autogen/` ぎč‡Ēå‹•į”Ÿæˆåž‹ã‚’æœ€æ–°åŒ–ã™ã‚‹ãŸã‚ãŽã‚ŗãƒžãƒŗãƒ‰ã€‚å†…éƒ¨ã§ `pnpm build-misskey-js-with-types` (backend build → `api.json` į”Ÿæˆ → misskey-js åž‹į”Ÿæˆ → ビãƒĢド → API extractor) を一æ‹ŦåŽŸčĄŒã™ã‚‹ã€‚
## įžåœ¨ãŽįŠļ態 (å†į”Ÿæˆå‰)
- įžãƒ–ãƒŠãƒŗãƒ: !`git branch --show-current`
- æ—ĸ存ぎ misskey-js é–ĸé€Ŗå¤‰æ›´: !`git status --short -- packages/misskey-js/`
## ã‚ŋ゚ク
äģĨ下ぎ手順を順į•ĒãĢåŽŸčĄŒã—ãĻください。
1. **å†į”ŸæˆãŽåŽŸčĄŒ**
`Bash` ツãƒŧãƒĢでäģĨä¸‹ãŽã‚ŗãƒžãƒŗãƒ‰ã‚’ `timeout: 600000` (10 分) を指厚しãĻåŽŸčĄŒã™ã‚‹ã€‚å†…éƒ¨ã§ backend ビãƒĢãƒ‰ã¨åž‹å†į”Ÿæˆã‚’čĄŒã†ãŸã‚ã€ãƒ‡ãƒ•ã‚ŠãƒĢトぎ 2 分ã‚ŋイムã‚ĸã‚Ļトでは不čļŗã™ã‚‹ã€‚
```bash
pnpm build-misskey-js-with-types
```
2. **åˇŽåˆ†ãŽįĸēčĒ**
厌äē†åžŒã€äģĨä¸‹ã‚’åŽŸčĄŒã—ãĻ `packages/misskey-js/src/autogen/` ãŽåˇŽåˆ†ã‚’įĸēčĒã™ã‚‹ (`built/` は `.gitignore` å¯žčąĄãĒぎでčŋŊčˇĄå¯žčąĄå¤–):
```bash
git status --short -- packages/misskey-js/
git diff --stat -- packages/misskey-js/src/autogen/
```
3. **įĩæžœå ąå‘Š**
- **åˇŽåˆ†ãĒし** → 「backend ぎ変更は misskey-js ぎå…Ŧ開型ãĢåŊąéŸŋしãĻã„ãžã›ã‚“ã€ã¨å ąå‘Šã™ã‚‹ã€‚čŋŊåŠ ã‚ŗãƒŸãƒƒãƒˆã¯ä¸čĻã€‚
- **åˇŽåˆ†ã‚ã‚Š** → å¤‰æ›´ãƒ•ã‚Ąã‚¤ãƒĢ一čĻ§ã‚’ãƒĻãƒŧã‚ļãƒŧãĢį¤ēし、`git add packages/misskey-js/src/autogen/` ã§å†į”Ÿæˆį‰Šã‚‚ã‚ŗãƒŸãƒƒãƒˆå¯žčąĄãĢåĢã‚ã‚‹ã‚ˆã†æĄˆå†…ã™ã‚‹ã€‚`api.json` ãŽåˇŽåˆ†ãŒå¤§ãã„å ´åˆã¯ã€API endpoint 側ぎ `meta` / `paramDef` / `res` åŽšįžŠã‚’įĸēčĒã™ã‚‹ã‚ˆã†äŋƒã™ã€‚
## æŗ¨æ„
- ã“ãŽã‚ŗãƒžãƒŗãƒ‰ã¯ **backend įˇ¨é›†åžŒãŽįĸēčĒ** ãŒį›Žįš„ã€‚backend を変更しãĻいãĒいぎãĢčĩ°ã‚‰ã›ã‚‹ã¨ã€ãƒ“ãƒĢãƒ‰ã‚­ãƒŖãƒƒã‚ˇãƒĨæŦĄįŦŦで no-op ãĢãĒる。
- åŽŸčĄŒä¸­ã¯ `packages/backend/built/` や `packages/misskey-js/built/` ãĒãŠãŽä¸­é–“į”Ÿæˆį‰ŠãŒæ›´æ–°ã•ã‚Œã‚‹ãŒã€ã“ã‚Œã‚‰ã¯ `.gitignore` å¯žčąĄã€‚
- į”Ÿæˆį‰ŠäģĨ外 (`packages/misskey-js/src/` ãŽã†ãĄ `autogen/` äģĨ外) ãĢä爿œŸã›ãŦåˇŽåˆ†ãŒå‡ēた場合は、ロãƒŧã‚ĢãƒĢãŽįˇ¨é›†ãŒæˇˇå…ĨしãĻいる可čƒŊ性があるため、一æ—Ļ中æ­ĸしãĻ原因をčĒŋæŸģする。

View File

@@ -1,146 +0,0 @@
---
description: Misskey ぎ .claude/ ハãƒŧネ゚ (skills/agents/commands) を 7 ã‚ĢテゴãƒĒã§æŽĄį‚šã™ã‚‹įĸēåŽšįš„ãĒᛪæŸģ。
argument-hint: "[repo|skills|commands|agents]"
---
<!--
SPDX-License-Identifier: MIT
SPDX-FileCopyrightText: 2026 Affaan Mustafa and everything-claude-code contributors
å‡ē典 (upstream): https://github.com/affaan-m/everything-claude-code (v2.0.0-rc.1)
upstream path: commands/harness-audit.md
upstream license: MIT — https://github.com/affaan-m/everything-claude-code/blob/main/LICENSE
project-level notice: see .claude/THIRD_PARTY_LICENSES.md (Misskey 内ã‚ĩãƒŧドパãƒŧãƒ†ã‚Ŗä¸€čϧ + MIT 全文)
Imported into Misskey .claude/ on 2026-05-10. The 7-category rubric and output contract are derived from the upstream ECC version (MIT). The runtime layer was substantially reimplemented for Misskey: the upstream relies on scripts/harness-audit.js to mechanically score, while this version asks Claude to score directly with pnpm/git/grep, and adds Misskey-specific evaluation axes (SPDX coverage / endpoint-list į™ģ錞æŧã‚Œ / migration 順åē / ja-JP.yml 整合).
note: 元 ECC į‰ˆã¯ scripts/harness-audit.js (専ᔍ Node ゚クãƒĒプト) で抟æĸ°æŽĄį‚šã—ãĻいたが、Misskey は ECC plugin runtime ãĢ䞝存しãĒい斚針ãĒぎで、Claude ãŒį›´æŽĨãƒ•ã‚Ąã‚¤ãƒĢをčĒ­ã‚“ã§æŽĄį‚šã™ã‚‹æ‰‹å‹•é‹į”¨į‰ˆãĢ書き換えた。Misskey å›ē有ぎ重čρčĻŗį‚š (SPDX éŠį”¨įŽ‡ / endpoint-list į™ģ錞æŧã‚Œ / migration 順åē / ja-JP.yml 整合) ã‚’čŠ•äžĄčģ¸ã¨ã—ãĻ明į¤ēįš„ãĢįĩ„ãŋčžŧんでいる。
-->
# /harness-audit — Misskey ハãƒŧãƒã‚šį›ŖæŸģ
Misskey ãƒĒポジトãƒĒぎ `.claude/` 構成を 7 ã‚ĢテゴãƒĒã§æŽĄį‚šã—ã€æ”šå–„å„Ē先åēĻを提į¤ēする。
## Usage
`/harness-audit [scope]`
- `scope` (äģģæ„): `repo` (default) / `skills` / `commands` / `agents`
## 評価ã‚ĢテゴãƒĒ (各 0-10)
| # | ã‚ĢテゴãƒĒ | 評価čģ¸ |
| --- | --- | --- |
| 1 | Tool Coverage | skill / agent / command ぎ数、æŦ ã‘ãĻいるワãƒŧクフロãƒŧæŽĩã€é‡č¤‡ãĒし |
| 2 | Context Efficiency | frontmatter description ãŽå†—é•ˇåēĻ、SKILL.md ãŽé•ˇã•åˆ†å¸ƒã€é‡č¤‡æƒ…å ąã€CLAUDE.md ぎč‚Ĩ大化 |
| 3 | Quality Gates | Stop / PreToolUse / PostToolUse hook ぎ整備、`/quality-gate` į­‰ãŽåŽŒäē†å‰ã‚˛ãƒŧãƒˆãŽæœ‰į„Ąã€č‡Ē動 lint/typecheck |
| 4 | Memory Persistence | docs/* ぎ同期įŠļæ…‹ã‚’čŠ•äžĄã€‚ãƒ—ãƒ­ã‚¸ã‚§ã‚¯ãƒˆå´ `.claude/memory/` はæœĒæŽĄį”¨æ–šé‡ (auto-memory はãƒĻãƒŧã‚ļãƒŧホãƒŧム側でč‡Ē動運ᔍ) ãŽãŸã‚ã€ã“ã“ã‚’æŽĄį‚ščĩˇį‚šãĢせずæ—ĸ厚 5/10 から開始する |
| 5 | Eval Coverage | testing.md ぎįļ˛įž…、Misskey å›ē有ぎ e2e/fed/Storybook/Cypress éŠį”¨ã‚Ŧイド |
| 6 | Security Guardrails | SPDX čĻį´„éŠį”¨ã€migration 不変性ãƒĢãƒŧãƒĢ、ja-JP.yml é™åŽšįˇ¨é›†ãƒĢãƒŧãƒĢ、secrets 検å‡ē |
| 7 | Cost Efficiency | enabledPlugins ãŽé‡č¤‡ãƒģ過剰、context-budget ぎ整備、MCP 過剰į™ģ錞ãĒし |
## Misskey å›ē有ぎįĸēčĒé …į›Ž (æŽĄį‚šæ šæ‹ ã‚ŗãƒžãƒŗãƒ‰)
æŽĄį‚šæ™‚ãĢäģĨä¸‹ã‚’åŽŸã‚ŗãƒžãƒŗãƒ‰ã§įĸēčĒã™ã‚‹ã€‚å„é …į›ŽãŽ **åąžã™ã‚‹ã‚ĢテゴãƒĒ** ã¯é …į›Žå†…ãĢæ˜Žč¨˜ã™ã‚‹ (#1-#3 は Security Guardrails、#4 は Tool Coverage、#5 は Quality Gates):
```bash
# 1. [Security Guardrails] SPDX éŠį”¨įŽ‡ (新čĻãƒ•ã‚Ąã‚¤ãƒĢæƒŗåŽšãŽæąŽį”¨ãƒã‚§ãƒƒã‚¯)
# - node_modules を prune で除外
# - packages/misskey-js は MIT ã‚ĩãƒ–ãƒ‘ãƒƒã‚ąãƒŧジãĒぎで AGPL ヘッダãƒŧを持たãĒい (AGENTS.md §1) → 除外
# - built/ ãĒおも除外
# å€™čŖœãĢはãĒお *.config.{ts,js} / *eslint* / *.d.ts ぎようãĒ CI 上 SPDX å¯žčąĄå¤–
# (.github/workflows/check-spdx-license-id.yml ぎ exclude å‚į…§) ã‚‚æˇˇã–ã‚‹ãŸã‚ã€
# 上äŊãĢå‡ēãŸãƒ•ã‚Ąã‚¤ãƒĢが「新čĻčŋŊåŠ ã—ãŸåŽŸã‚ŗãƒŧãƒ‰ã€ã‹ãŠã†ã‹ã¯į›ŽčĻ–åˆ¤åŽšã™ã‚‹ã€‚
find packages \
\( -type d \( -name node_modules -o -name built -o -name dist -o -path 'packages/misskey-js' \) -prune \) \
-o -type f \( -name '*.ts' -o -name '*.js' -o -name '*.vue' -o -name '*.scss' \) -print \
| xargs -r grep -L 'SPDX-License-Identifier: AGPL-3.0-only' | head -20
# → 上äŊãĢ新čĻåŽŸã‚ŗãƒŧãƒ‰ãŒį„Ąã‘ã‚Œã°æē€į‚š
# 2. [Security Guardrails] ja-JP.yml äģĨ外ぎ locales ãŒį›´čŋ‘ã§æ‰‹å‹•įˇ¨é›†ã•ã‚ŒãĻいãĒいか
# --pretty=format: ã§ã‚ŗãƒŸãƒƒãƒˆãƒ˜ãƒƒãƒ€čĄŒã‚’æŠ‘æ­ĸã—ã€ãƒ•ã‚Ąã‚¤ãƒĢåčĄŒãŽãŋを掋しãĻから grep する。
# Crowdin ぎč‡Ē動同期 commit でもäģ–言čĒž yml は更新されるため、å‡ē力が 0 行ãĢãĒることは少ãĒい。
# å‡ēåŠ›ãŒã‚ãŖãŸå ´åˆã¯ã€author / commit message をįĸēčĒã— Crowdin į”ąæĨã‹æ‰‹å‹•įˇ¨é›†ã‹ã‚’åˆ¤åŽšã™ã‚‹:
# git log --since='30 days ago' --pretty=format:'%h %an %s' -- locales/<file>.yml
git log --since='30 days ago' --pretty=format: --name-only -- 'locales/*.yml' \
| grep -v '^$' | grep -v 'ja-JP.yml' | sort -u
# → å‡ēåŠ›ãŒį„Ąã„ã€ãžãŸã¯å…¨ãĻ Crowdin į”ąæĨ commit ãĒらæē€į‚š
# 3. [Security Guardrails] migration ぎ pending DDL 検æŸģ (TypeORM schema builder)
pnpm --filter backend check-migrations
# → 0 errors (= "All migrations are clean.") ãĒらæē€į‚š
# 4. [Tool Coverage] endpoint-list.ts į™ģ錞æŧã‚Œ (新čĻ endpoint がãƒĒ゚トãĢãĒい場合)
# endpoints/ は再帰構造 (notes/create.ts, admin/announcements/create.ts į­‰) で 400+ ãƒ•ã‚Ąã‚¤ãƒĢあるため、
# endpoint-list.ts も `export * as '<category>/<name>' from './endpoints/<category>/<name>.js';` åŊĸåŧã§
# 1 ãƒ•ã‚Ąã‚¤ãƒĢ 1 行į™ģéŒ˛ã•ã‚Œã‚‹ã€‚ä¸Ąč€…ãŽčĄŒæ•°ã‚’ã€Œå†å¸° .ts 数」と「export * as čĄŒæ•°ã€ã§æ¯”čŧƒã™ã‚‹ã€‚
# e2e / 単äŊ“テ゚トは endpoint ではãĒいぎで *.test.ts を除外する。
endpoint_files=$(find packages/backend/src/server/api/endpoints -type f -name '*.ts' ! -name '*.test.ts' | wc -l)
list_entries=$(grep -cE "^export \* as " packages/backend/src/server/api/endpoint-list.ts)
echo "endpoints (recursive): $endpoint_files / endpoint-list.ts entries: $list_entries"
# åˇŽåˆ†ãŒ 0 ãĒらæē€į‚šã€‚åˇŽåˆ†ãŒå‡ēたら、į™ģ錞æŧã‚ŒãŽå…ˇäŊ“į‰šåޚ:
comm -23 \
<(find packages/backend/src/server/api/endpoints -type f -name '*.ts' ! -name '*.test.ts' \
| sed -E 's|.*/endpoints/||;s|\.ts$||' | sort -u) \
<(grep -oE "^export \* as '[^']+'" packages/backend/src/server/api/endpoint-list.ts \
| sed -E "s/^export \* as '([^']+)'/\1/" | sort -u)
# å‡ēåŠ›ã•ã‚ŒãŸčĄŒãŒį™ģ錞æŧã‚ŒãŽ endpoint。0 行ãĒらæē€į‚šã€‚
# 5. [Quality Gates] console.log ãŽæˇˇå…Ĩ
grep -rn 'console\.\(log\|debug\)' packages/backend/src packages/frontend/src 2>/dev/null \
| grep -v 'node_modules\|test\|.spec\.\|.test\.' | wc -l
# → 0 ãŒį†æƒŗ
```
## å‡ē力åĨ‘į´„
äģĨ下をčŋ”す:
1. `overall_score` / `max_score` (repo は 70 į‚šæē€į‚š)
2. ã‚ĢテゴãƒĒã”ã¨ãŽã‚šã‚ŗã‚ĸ + å…ˇäŊ“įš„ãĒæ šæ‹ 
3. å¤ąæ•—ãƒã‚§ãƒƒã‚¯é …į›Žã¨čŠ˛åŊ“ãƒ•ã‚Ąã‚¤ãƒĢパ゚
4. Top 3 攚善ã‚ĸã‚¯ã‚ˇãƒ§ãƒŗ
5. æŦĄãĢéŠį”¨ã‚’æŽ¨åĨ¨ã™ã‚‹ skill / 手順
## ã‚ĩãƒŗãƒ—ãƒĢå‡ē力
```text
Harness Audit (repo): 55/70
Tool Coverage: 9/10 (skills 5, agents 2, commands 5 — 偏りãĒし)
Context Efficiency: 8/10 (description åšŗå‡ 3-5 čĄŒã€č‚Ĩ大ãĒし)
Quality Gates: 5/10 (Stop hook å…ąæœ‰č¨­åŽšãĢæœĒį™ģ錞 / `/quality-gate` あり)
Memory Persistence: 5/10 (プロジェクト側 memory/ æœĒæŽĄį”¨æ–šé‡ = æ—ĸ厚値)
Eval Coverage: 7/10 (testing.md įļ˛įž…、Storybook 一部抜け)
Security Guardrails: 10/10 (SPDX 100%, locales OK, migrations clean)
Cost Efficiency: 8/10 (context-budget 導å…Ĩ済 / MCP 0)
Failed Checks:
- packages/frontend/src/.../X.vue で SPDX æŦ čŊ (Security Guardrails)
- console.log が backend ãĢ 3 äģļ (Quality Gates)
- å…ąæœ‰ Stop hook ãĒし (Quality Gates) — 各 contributor が `.claude/settings.local.json` で opt-in する斚針ãĒã‚‰æ¸›į‚šã—ãĒくãĻč‰¯ã„
Top 3 Actions:
1) [Security Guardrails] SPDX æŦ čŊ 1 ãƒ•ã‚Ąã‚¤ãƒĢをäŋŽæ­Ŗ:
packages/frontend/src/.../X.vue
2) [Quality Gates] backend ぎ console.log 3 äģļを logger ãĢįŊŽæ›ã€‚
git grep "console\.log" packages/backend/src
3) [Cost Efficiency] enabledPlugins からæœĒäŊŋį”¨ãŽã‚‚ãŽã‚’å¤–ã™ã€‚
.claude/docs/plugins.md ã¨į…§åˆã€‚
Suggested next skills to apply:
- /quality-gate で厌äē†å‰ãĢ lint + unit test を回す
- context-budget で plugin į”ąæĨぎ overhead をįĸēčĒ
```
## æŽĄį‚šãŽäŋĄé ŧ性
- įĸēåŽšįš„: 同じ commit / 同じ `.claude/` 構成ãĒã‚‰åŒã˜ã‚šã‚ŗã‚ĸ
- ヒãƒĨãƒŧãƒĒã‚šãƒ†ã‚Ŗã‚¯ã‚š: 「description ãŽå†—é•ˇåēĻ」ぎようãĒä¸ģčĻŗé …į›Žã¯åŒä¸€åŸēæē–で抟æĸ°įš„ãĢ判厚
- ゚クãƒĒプト不čρ: `pnpm` と `git`、`grep`/`find` į­‰ãŽæ¨™æē–ツãƒŧãƒĢぎãŋ
## å‚č€ƒ: ECC ã‚ĒãƒĒジナãƒĢã¨ãŽåˇŽåˆ†
- ECC į‰ˆã¯ `node scripts/harness-audit.js` ã‚’į›´åŠãã™ã‚‹é‹į”¨ã§ã€ECC ãƒĒポジトãƒĒ全äŊ“ãĢé–‰ã˜ãŸæŽĄį‚šã ãŖãŸã€‚
- Misskey į‰ˆã¯ **Misskey ぎčĻį´„ (SPDX/migration/locales/endpoint-list)** を Security æŽĄį‚šãĢįĩ„ãŋčžŧãŋ、`pnpm` ベãƒŧã‚šãŽåŽŸã‚ŗãƒžãƒŗãƒ‰ã§æ šæ‹ ã‚’å–ã‚‹æ–šåŧãĢå†č¨­č¨ˆã€‚
- įĩæžœã¨ã—ãĻ ECC へぎ䞝存はã‚ŧロ。

View File

@@ -1,81 +0,0 @@
---
description: TypeORM migration ぎįŠē雛åŊĸã‚’į”Ÿæˆã™ã‚‹ã€‚ã‚šã‚­ãƒŧãƒžåˇŽåˆ†ã‹ã‚‰č‡Ēå‹•į”Ÿæˆã—ãŸã„æ™‚ã¯ create-migration skill をäŊŋうこと
argument-hint: <PascalCaseName>
allowed-tools: Bash(pnpm:*), Bash(ls:*), Bash(test:*), Bash(head:*), Read, Edit
---
## åŧ•æ•°
åŧ•æ•°: `$ARGUMENTS`
## ã‚ŋ゚ク
1. **PascalCaseName ぎ検č¨ŧ**
`$ARGUMENTS` が `^[A-Z][A-Za-z0-9]+$` ãĢä¸€č‡´ã™ã‚‹ã‹įĸēčĒã™ã‚‹ã€‚ä¸€č‡´ã—ãĒい場合はエナãƒŧįĩ‚äē†ã—、`AddFooBar` / `BirthdayIndex` ぎようãĒåŊĸåŧã‚’æĄˆå†…ã™ã‚‹ã€‚
2. **æ—ĸå­˜ãƒ•ã‚Ąã‚¤ãƒĢぎ存在įĸēčĒ**
```bash
ls packages/backend/migration/*$ARGUMENTS.{js,ts} 2>/dev/null
```
æ—ĸãĢ同名 (ã‚ŋイム゚ã‚ŋãƒŗãƒ—é•ã„) ãŽãƒ•ã‚Ąã‚¤ãƒĢが存在する場合、上書きせずãƒĻãƒŧã‚ļãƒŧãĢåˆĨ名をäŋƒã™ã€‚
3. **TypeORM å…Ŧåŧ CLI でįŠē雛åŊĸã‚’į”Ÿæˆ (`-o --esm` åŋ…é ˆ)**
`create-migration` skill ぎ斚針ãĢ垓い、`Date.now()` を手書きするぎではãĒく TypeORM CLI をäŊŋう。`-o --esm` で **最初から JS(ESM) ã‚’į”Ÿæˆ** させ、垌įļšãŽ `.ts → .js` 変換や `import { MigrationInterface }` å‰Šé™¤ã¨ã„ãŖãŸ TS å›ē有構文ぎ除åŽģを不čρãĢする (`-o --esm` をäģ˜ã‘ãĒいと `.ts` + CommonJS / `implements MigrationInterface` äģ˜ãã§į”Ÿæˆã•れ、Misskey ぎ `ormconfig.js` (`migration/*.js` ぎãŋロãƒŧド) とæ—ĸ存 migration ゚ã‚ŋイãƒĢãĢ合わãĒい):
```bash
pnpm --filter backend exec typeorm migration:create -o --esm migration/$ARGUMENTS
```
å‡ē力: `packages/backend/migration/<UnixMs>-<PascalCaseName>.js`
4. **į”Ÿæˆãƒ•ã‚Ąã‚¤ãƒĢパ゚ぎ取垗**
垌įļšã‚šãƒ†ãƒƒãƒ—でäŊŋうパ゚を変数ãĢ受ける (`<ms>` を手書きしãĒい):
```bash
dst=$(ls -t packages/backend/migration/*$ARGUMENTS.js | head -1)
```
äģĨ降ぎ゚テップでは `$dst` ã‚’įˇ¨é›†å¯žčąĄã¨ã—ãĻæ‰ąã†ã€‚åŽŒæˆåžŒãŽå…¸åž‹įš„ãĒåŊĸはæŦĄãŽã‚ˆã†ãĢãĒる (å‚č€ƒ: [packages/backend/migration/1767169026317-birthday-index.js](../../packages/backend/migration/1767169026317-birthday-index.js)):
```js
export class <PascalCaseName><ms> {
name = '<PascalCaseName><ms>'
async up(queryRunner) {
}
async down(queryRunner) {
}
}
```
5. **SPDX ヘッダãƒŧぎčŋŊ加**
`Edit` ツãƒŧãƒĢã§ã€ãƒ•ã‚Ąã‚¤ãƒĢ冒頭ãĢäģĨ下をæŒŋå…Ĩする。CI ぎ `spdx` ã‚¸ãƒ§ãƒ–ãŒå¤ąæ•—ã™ã‚‹ãŸã‚åŋ…é ˆ:
```js
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
```
6. **migration ぎ pending DDL 検æŸģ**
```bash
pnpm --filter backend check-migrations
```
TypeORM schema builder で pending DDL を検å‡ēする検æŸģ ([scripts/check_migrations_clean.js](../../packages/backend/scripts/check_migrations_clean.js))。įŠē雛åŊĸをäŊœãŖãŸã ã‘ぎæŽĩéšŽã§ã¯ã‚¨ãƒŗãƒ†ã‚Ŗãƒ†ã‚ŖåˇŽåˆ†ã¨ãŽä¸æ•´åˆãŒæŽ‹ã‚‹å ´åˆãŒã‚ã‚‹ãŸã‚ã€`up`/`down` を埋めた垌ãĢã‚‚å†åŽŸčĄŒã—ãĻ 0 äģļãĢãĒるかįĸēčĒã™ã‚‹ã€‚
7. **įĩæžœå ąå‘Š**
- į”Ÿæˆãƒ•ã‚Ąã‚¤ãƒĢパ゚をį¤ēす。
- `up()` / `down()` ぎ中čēĢがįŠēであることをäŧãˆã€SQL を書くåŋ…čĻãŒã‚ã‚‹ã¨æĄˆå†…ã™ã‚‹ã€‚
- `down()` をįŠēぎぞぞ攞įŊŽã™ã‚‹ã¨æœŦį•ĒロãƒŧãƒĢバック時ãĢčŠ°ã‚€ãŸã‚ã€åŋ…ず `up` ぎ厌全ãĒåˇģきæˆģã—ã‚’åŽŸčŖ…ã™ã‚‹ã‚ˆã†äŋƒã™ã€‚
- čŠŗį´°ãĒ手順 (`migration:generate` をäŊŋã†ãšãã‚ąãƒŧ゚、CONCURRENTLY ãĒãŠãŽæŗ¨æ„į‚š) は `create-migration` skill ã‚’å‚į…§ã™ã‚‹ã‚ˆã†æĄˆå†…ã™ã‚‹ã€‚
## æŗ¨æ„
- ã“ãŽã‚ŗãƒžãƒŗãƒ‰ã¯ **įŠē雛åŊĸã‚’į´ æ—Šãå‡ēしãĻ手書きする** į”¨é€”ã€‚ã‚¨ãƒŗãƒ†ã‚Ŗãƒ†ã‚Ŗ (`packages/backend/src/models/*.ts`) ã‚’å¤‰æ›´ã—ãŸåˇŽåˆ†ã‹ã‚‰ SQL をč‡Ēå‹•į”Ÿæˆã—ãŸã„å ´åˆã¯ã€ã“ãŽã‚ŗãƒžãƒŗãƒ‰ã§ã¯ãĒく `create-migration` skill įĩŒį”ąã§ `migration:generate` をäŊŋうこと。
- マãƒŧジ済ãŋ migration ãƒ•ã‚Ąã‚¤ãƒĢはįĩļ寞ãĢįˇ¨é›†ã—ãĒい ([AGENTS.md §3](../../AGENTS.md#3-マãƒŧジ済ãŋ-migration-をįĩļ寞ãĢįˇ¨é›†ã—ãĒい))。

View File

@@ -1,122 +0,0 @@
---
description: Misskey ぎ lint / typecheck / éĢ˜é€Ÿãƒ†ã‚šãƒˆã‚’é †ãĢåŽŸčĄŒã—ãĻ品čŗĒã‚˛ãƒŧãƒˆã‚’é€šã™ã‚ŗãƒžãƒŗãƒ‰ã€‚åŽŒäē†å‰ãŽčģŊ量検č¨ŧį”¨ã€‚
argument-hint: "[repo|backend|frontend|<path/to/file.ts>]"
---
<!--
SPDX-License-Identifier: MIT
SPDX-FileCopyrightText: 2026 Affaan Mustafa and everything-claude-code contributors
å‡ē典 (upstream): https://github.com/affaan-m/everything-claude-code (v2.0.0-rc.1)
upstream path: commands/quality-gate.md
upstream license: MIT — https://github.com/affaan-m/everything-claude-code/blob/main/LICENSE
project-level notice: see .claude/THIRD_PARTY_LICENSES.md (Misskey 内ã‚ĩãƒŧドパãƒŧãƒ†ã‚Ŗä¸€čϧ + MIT 全文)
Imported into Misskey .claude/ on 2026-05-10. Pipeline æĻ‚åŋĩ (lint → typecheck → test) は upstream ECC į‰ˆã‹ã‚‰å€Ÿį”¨ (MIT)ã€‚åŽŸã‚ŗãƒžãƒŗãƒ‰åą¤ã¯ Misskey ぎ pnpm + tsgo + ESLint + Vitest ãĢå›ē厚し、formatter (Prettier/Biome) フェãƒŧã‚ēは削除した。
note: 元 ECC į‰ˆã¯č¨€čĒžč‡Ē動判厚 + format/lint/type ぎジェネãƒĒãƒƒã‚¯į‰ˆã ãŖãŸãŒã€Misskey 専ᔍãĢ pnpm + tsgo + ESLint + Vitest ぎįĩ„ãŋ合わせãĢå›ē厚。重い test:e2e / test:fed はåĢぞãĒい (CI å´ã§åŽŸčĄŒã•ã‚Œã‚‹)。
-->
# /quality-gate — Misskey čģŊ量品čŗĒã‚˛ãƒŧト
`/quality-gate [scope]`
厌äē†å‰ãŽ **čģŊ量** 品čŗĒチェック。重い E2E / é€Ŗåˆãƒ†ã‚šãƒˆ (test:e2e / test:fed / Cypress) は CI å´ã§åŽŸčĄŒã•ã‚Œã‚‹ãŸã‚ã€æœŦã‚ŗãƒžãƒŗãƒ‰ãĢはåĢめãĒい。
## Scope
- `repo` (default) — å…¨ãƒ‘ãƒƒã‚ąãƒŧジ
- `backend` — `packages/backend` ぎãŋ
- `frontend` — `packages/frontend` ぎãŋ
- `path/to/file.ts` — å˜ä¸€ãƒ•ã‚Ąã‚¤ãƒĢへぎ ESLint --fix ぎãŋ
## Pipeline
### Repo scope (全部)
å„ãƒ‘ãƒƒã‚ąãƒŧジぎ `lint` ゚クãƒĒプト原äŊ“は `pnpm typecheck && pnpm eslint` ([packages/backend/package.json](../../packages/backend/package.json), [packages/frontend/package.json](../../packages/frontend/package.json)) で、ãƒĢãƒŧトぎ `pnpm lint` は `pnpm --no-bail -r lint` (= å…¨ãƒ‘ãƒƒã‚ąãƒŧジで lint を `--no-bail` ã§åŽŸčĄŒ)。**typecheck は lint ãĢåĢぞれãĻいる**ため、通常はこぎ 2 ã‚ŗãƒžãƒŗãƒ‰ã§ååˆ†:
```bash
# 1. Lint (= typecheck + ESLintã€å…¨ãƒ‘ãƒƒã‚ąãƒŧジ。--no-bail ã§æœ€åˆãŽå¤ąæ•—ã§æ­ĸぞらず全įĩæžœã‚’集める)
pnpm lint
# 2. Unit test (éĢ˜é€Ÿã€e2e はåĢぞãĒい)
pnpm --filter backend test
pnpm --filter frontend test
```
#### čŠŗį´°ã‚’åˆ†ã‘ãĻčĻ‹ãŸã„æ™‚ãŽãŋ (optional)
lint がぞとめãĻå¤ąæ•—ã—ãĻいãĻ typecheck ぎįĩæžœã ã‘単į‹ŦでčĻ‹ãŸã„å ´åˆã¯ã€äģĨ下を個åˆĨãĢ回す。**通常は不čρ** (lint ぎå‡ē力をčĒ­ã‚ã°čļŗã‚Šã‚‹):
```bash
pnpm --filter backend typecheck # tsgo 単äŊ“
pnpm --filter frontend typecheck # vue-tsc 単äŊ“ (Vue SFC ぎ型をčĻ‹ã‚‹ãŸã‚)
```
### Backend scope
`pnpm --filter backend lint` は内部で `pnpm typecheck && pnpm eslint` ã‚’åŽŸčĄŒã™ã‚‹ ([packages/backend/package.json](../../packages/backend/package.json)) ぎで、`lint` を回せば typecheck もįĩ‚わる。čģŊé‡ã‚˛ãƒŧトでは typecheck ぎäēŒé‡åŽŸčĄŒã‚’éŋけるため `lint` + `test` ぎãŋ:
```bash
pnpm --filter backend lint
pnpm --filter backend test
```
`tsgo` ぎå‡ē力を単į‹ŦでčĻ‹ãŸã„æ™‚ãŽãŋ optional で `pnpm --filter backend typecheck` をåˆĨ途回す。
### Frontend scope
`pnpm --filter frontend lint` も内部で `pnpm typecheck && pnpm eslint` ã‚’åŽŸčĄŒã™ã‚‹ ([packages/frontend/package.json](../../packages/frontend/package.json)) ため、čģŊé‡ã‚˛ãƒŧトでは Backend 同様ãĢ `lint` + `test` ぎãŋ:
```bash
pnpm --filter frontend lint
pnpm --filter frontend test
```
`vue-tsc` ぎå‡ē力を単į‹ŦでčĻ‹ãŸã„æ™‚ãŽãŋ optional で `pnpm --filter frontend typecheck` をåˆĨ途回す。
### Single file scope
```bash
pnpm exec eslint --fix <path>
```
## Output
åŽŸčĄŒã—ãŸãƒ•ã‚§ãƒŧã‚ēぎ pass/fail とäģļæ•°ã‚’é›†č¨ˆã™ã‚‹ã€‚æ¨™æē–ãƒ‘ã‚¤ãƒ—ãƒŠã‚¤ãƒŗã¯ `pnpm lint` (typecheck 内包) と unit test ぎãŋãĒぎで、デフりãƒĢトぎå‡ē力はäģĨ下ぎようãĢãĒる:
```text
Quality Gate (repo):
Lint: PASS (0 errors, 2 warnings)
Backend ut: PASS (412/412)
Frontend ut: PASS (87/87)
→ 厌äē†å‰ãŽčģŊ量チェック OK。重い e2e / é€Ŗåˆãƒ†ã‚šãƒˆã¯ CI å´ã§åŽŸčĄŒã•ã‚Œã‚‹ã€‚
```
`#### čŠŗį´°ã‚’åˆ†ã‘ãĻčĻ‹ãŸã„æ™‚ãŽãŋ (optional)` で個åˆĨ typecheck (`pnpm --filter backend typecheck` / `pnpm --filter frontend typecheck`) も回した場合ぎãŋ、そぎįĩæžœã‚’čŋŊåŠ čĄŒã¨ã—ãĻ襨į¤ēする:
```text
Quality Gate (repo):
Lint: PASS (0 errors, 2 warnings)
Backend tc: PASS (0 errors) # optional åŽŸčĄŒæ™‚ãŽãŋ
Frontend tc: PASS (0 errors) # optional åŽŸčĄŒæ™‚ãŽãŋ
Backend ut: PASS (412/412)
Frontend ut: PASS (87/87)
```
å¤ąæ•—æ™‚ã¯æœ€åˆãĢčŊãĄãŸãƒ•ã‚§ãƒŧã‚ēで停æ­ĸしãĻčŠŗį´°ã‚’čĻ‹ã›ã‚‹ã€‚
## é–ĸ逪 skill / ã‚ŗãƒžãƒŗãƒ‰
- `/check-misskey-js` ã‚ŗãƒžãƒŗãƒ‰ — API 変更時ぎ misskey-js å†į”Ÿæˆ
- [AGENTS.md §åŋ…é ˆã‚ŗãƒžãƒŗãƒ‰](../../AGENTS.md#åŋ…é ˆã‚ŗãƒžãƒŗãƒ‰) — pnpm ã‚ŗãƒžãƒŗãƒ‰ä¸€čĻ§ãŽæ­Ŗå…¸
## 元 ECC į‰ˆã¨ãŽåˇŽåˆ†
- ジェネãƒĒックãĒ言čĒžč‡Ē動判厚を排除し、Misskey å›ē厚 pipeline ãĢ。
- formatter フェãƒŧã‚ēãĒし (Misskey は ESLint --fix ぎãŋæŽĄį”¨)。
- e2e / federation / Cypress は重いため除外し CI 側ãĢå§”č­˛ã€‚

View File

@@ -1,18 +0,0 @@
# Misskey – Claude Code čŖœåŠŠãƒ‰ã‚­ãƒĨãƒĄãƒŗãƒˆ
ãƒĢãƒŧト `CLAUDE.md` ãĢは書かれãĻいãĒいが、開į™ē時ãĢå‚į…§ã™ã‚‹ã¨äžŋ刊ãĒæƒ…å ąã‚’åˆ†é‡ŽåˆĨãĢぞとめãĻいる。**Claude はåŋ…čρãĢãĒãŖãŸã‚ŋã‚¤ãƒŸãƒŗã‚°ã§čŠ˛åŊ“ãƒ•ã‚Ąã‚¤ãƒĢを Read ã™ã‚Œã°č‰¯ã„** (auto-load しãĒい)。
## į´ĸåŧ•
| ãƒ•ã‚Ąã‚¤ãƒĢ | いつčĒ­ã‚€ã‹ |
|---|---|
| [architecture.md](./architecture.md) | ãƒ‘ãƒƒã‚ąãƒŧジ構成ãƒģビãƒĢãƒ‰æ§‹é€ ã‚’æŠŠæĄã—ãŸã„æ™‚ / æ–°ãƒ‘ãƒƒã‚ąãƒŧã‚¸ã‚’čˇ¨ãå¤‰æ›´ã‚’č¨ˆį”ģする時 |
| [backend.md](./backend.md) | `packages/backend` ã‚’įˇ¨é›†ã™ã‚‹æ™‚ (NestJS / TypeORM / API endpoint / migration) |
| [frontend.md](./frontend.md) | `packages/frontend` ã‚’įˇ¨é›†ã™ã‚‹æ™‚ (Vue 3 / Mk* / i18n / SCSS Modules / `os.ts`) |
| [testing.md](./testing.md) | テ゚トを書くãƒģčĩ°ã‚‰ã›ã‚‹æ™‚ (Vitest 構成、Cypress、Storybook) |
| [plugins.md](./plugins.md) | 有劚化済ぎ Claude Code ãƒ—ãƒŠã‚°ã‚¤ãƒŗãŽį”¨é€”ã‚’įĸēčĒã—ãŸã„æ™‚ |
## 誜čļŗ: ãƒĢãƒŧãƒĢ vs ドキãƒĨãƒĄãƒŗãƒˆ
- ä狿•…į›´įĩãƒĢãƒŧãƒĢ (SPDX / locales / migration) とåŋ…é ˆã‚ŗãƒžãƒŗãƒ‰ãƒģCHANGELOG 書åŧã¯ã€ãƒĒポジトãƒĒãƒĢãƒŧトぎ [AGENTS.md](../../AGENTS.md) ãĢé›†į´„ã•ã‚ŒãĻいる。Claude Code は CLAUDE.md からぎ `@AGENTS.md` ã§å¸¸æ™‚ã‚ŗãƒŗãƒ†ã‚­ã‚šãƒˆãĢ䚗せる。Codex / Copilot ã‚‚åŒã˜ãƒ•ã‚Ąã‚¤ãƒĢをčĒ­ã‚€ã€‚
- `.claude/docs/*.md` (ã“ãŽãƒ‡ã‚ŖãƒŦクトãƒĒ) は **ã‚Ēãƒŗãƒ‡ãƒžãƒŗãƒ‰å‚į…§**。Claude が「įŸĨãŖãĻãŠã„ãŸæ–šãŒč‰¯ã„ãŒå¸¸ãĢ持つåŋ…čĻã¯ãĒい」内厚をここãĢįŊŽãã€‚

View File

@@ -1,47 +0,0 @@
# ã‚ĸãƒŧã‚­ãƒ†ã‚¯ãƒãƒŖæĻ‚čρ
## ãƒĸノãƒŦポ構成 (pnpm workspaces)
pnpm workspace ãŽæ­Ŗã¯ [pnpm-workspace.yaml](../../pnpm-workspace.yaml) で、äģĨ下 11 ãƒ‘ãƒƒã‚ąãƒŧジと、`packages/misskey-js` 内ぎ sub-workspace `packages/misskey-js/generator` (åž‹į”Ÿæˆį”¨ãŽå†…éƒ¨ã‚¸ã‚§ãƒãƒŦãƒŧã‚ŋã€‚į›´æŽĨįˇ¨é›†ã—ãĒい) で構成される。`package.json` ぎ `workspaces` 配列もäŊĩč¨˜ã—ãĻいるが、原äŊ“は pnpm-workspace.yaml がčĒ­ãžã‚Œã‚‹:
| ãƒ‘ãƒƒã‚ąãƒŧジ | åŊšå‰˛ |
|---|---|
| `packages/backend` | NestJS 11 + Fastify 5 + TypeORM 0.3 (PostgreSQL) + Redis。HTTP/WebSocket/ActivityPub ã‚ĩãƒŧバãƒŧæœŦäŊ“。 |
| `packages/frontend` | Vue 3.5 + Vite。Web クナイã‚ĸãƒŗãƒˆæœŦäŊ“。 |
| `packages/frontend-embed` | 埋めčžŧãŋå°‚į”¨ãƒ“ãƒĨãƒŧ (ノãƒŧト単äŊ“プãƒŦビãƒĨãƒŧį­‰)。 |
| `packages/frontend-shared` | frontend と frontend-embed ã§å…ąæœ‰ã™ã‚‹ãƒĻãƒŧãƒ†ã‚ŖãƒĒãƒ†ã‚Ŗãƒģã‚ŗãƒŗãƒãƒŧãƒãƒŗãƒˆã€‚ |
| `packages/frontend-builder` | ãƒ•ãƒ­ãƒŗãƒˆã‚¨ãƒŗãƒ‰ãƒ“ãƒĢド支援 (Vite plugin ãĒお)。 |
| `packages/sw` | Service Worker。 |
| `packages/misskey-js` | JS/TS クナイã‚ĸãƒŗãƒˆ SDK (MIT ã‚ĩãƒ–ãƒ‘ãƒƒã‚ąãƒŧジ)。`src/autogen/` 配下ぎãŋ backend ぎ OpenAPI から `pnpm build-misskey-js-with-types` でč‡Ēå‹•į”Ÿæˆã•ã‚Œã€ãã‚ŒäģĨ外 (`src/index.ts` / `src/api.ts` į­‰) は手書きäŋåŽˆã™ã‚‹ã€‚autogen é…ä¸‹ã‚’į›´æŽĨįˇ¨é›†ã—ãĒいこと。 |
| `packages/misskey-reversi` | 内č”ĩãƒĒバãƒŧã‚ˇã‚˛ãƒŧムぎロジック。 |
| `packages/misskey-bubble-game` | 内č”ĩバブãƒĢã‚˛ãƒŧムぎロジック。 |
| `packages/i18n` | locales čĒ­ãŋčžŧãŋ/åž‹į”ŸæˆãŽã‚ĩポãƒŧト。 |
| `packages/icons-subsetter` | ã‚ĸã‚¤ã‚ŗãƒŗãŽã‚ĩブã‚ģット化ツãƒŧãƒĢ。 |
そぎäģ–ãĢ `packages/shared` (workspaces ãĢはåĢぞれãĒã„ãŒå…ąæœ‰ãƒ•ã‚Ąã‚¤ãƒĢįŊŽãå ´) もある。
## 重čρãĒ䞝存é–ĸäŋ‚
```
frontend ── misskey-js (auto-generated) ── backend (OpenAPI)
▲
└── frontend-embed, sw も䞝存
```
- backend ぎ API (meta / paramDef / response) を変更したら **åŋ…ず** `pnpm build-misskey-js-with-types` ã‚’åŽŸčĄŒã—ã€misskey-js ãŽį”Ÿæˆį‰Šã‚’æ›´æ–°ã™ã‚‹ã€‚åŋ˜ã‚Œã‚‹ã¨ CI ぎ `check-misskey-js-autogen` ジョブがčŊãĄã‚‹ã€‚
## ビãƒĢドツãƒŧãƒĢ
- **Backend**: `rolldown` (Rust čŖŊãƒģRollup äē’æ› API ãŽãƒãƒŗãƒ‰ãƒŠ) ã§ãƒãƒŗãƒ‰ãƒĢ。型チェックは `tsgo` (TypeScript native preview)。
- **Frontend**: Vite。型チェックは `vue-tsc`。
- **Lint**: ESLint 9 (Flat Config) + `@misskey-dev/eslint-plugin`。
## å›Ŋ際化
- `locales/` ᛴ䏋ãĢ 40 言čĒžãŽ YAML (ja-JP.yml + äģ– 39 言čĒž)。
- **`ja-JP.yml` ぎãŋæ‰‹å‹•įˇ¨é›†å¯** (Crowdin įĩŒį”ąã§äģ–言čĒžã¸č‡Ē動配äŋĄ)。
- ãƒ•ãƒ­ãƒŗãƒˆã‚¨ãƒŗãƒ‰ã‹ã‚‰ãŽå‚į…§ã¯åŧ•æ•°ãĒしかåŧ•数ありかでäŊŋã„åˆ†ã‘ã‚‹ã€‚čŠŗį´°ã¯ [frontend.md](./frontend.md#å›Ŋ際化-i18n)。
## ナイã‚ģãƒŗã‚š
ãƒĒポジトãƒĒæœŦäŊ“は AGPL-3.0-only。**AGPL-3.0-only įŽĄčŊ„かつ SPDX CI å¯žčąĄãƒ‡ã‚ŖãƒŦクトãƒĒ** ぎ新čĻ `.ts` / `.js` / `.cjs` / `.mjs` / `.vue` / `.scss` / `.html` ãƒ•ã‚Ąã‚¤ãƒĢãĢは冒頭ãĢ SPDX ヘッダãƒŧåŋ…須。`packages/misskey-js` は MIT ã‚ĩãƒ–ãƒ‘ãƒƒã‚ąãƒŧジãĒぎで AGPL ヘッダãƒŧを一型ãĢäģ˜ã‘ãĒã„ã€‚æĄäģļã¨é™¤å¤–ãŽčŠŗį´°ã¯ [AGENTS.md §1](../../AGENTS.md#1-spdx-ヘッダãƒŧåŋ…é ˆ) å‚į…§ã€‚

View File

@@ -1,124 +0,0 @@
# Backend (`packages/backend`) čĻį´„
NestJS 11 + Fastify 5 + TypeORM 0.3 (PostgreSQL) + Redis。
## ã‚ĸãƒŧã‚­ãƒ†ã‚¯ãƒãƒŖ
- **DI ã‚ŗãƒŗãƒ†ãƒŠ**: NestJS ぎ `@Injectable()` ã‚ĩãƒŧビ゚ + Repository (TypeORM) パã‚ŋãƒŧãƒŗã€‚
- **DI トãƒŧã‚¯ãƒŗ**: `@/di-symbols.js` ぎ `DI` から `@Inject(DI.xxx)` ã§æŗ¨å…Ĩ。
- **ビãƒĢド**: `rolldown -c` で `built/` ãĢãƒãƒŗãƒ‰ãƒĢ。型チェックは `tsgo`。
## API ã‚¨ãƒŗãƒ‰ãƒã‚¤ãƒŗãƒˆ
### 配įŊŽ
`packages/backend/src/server/api/endpoints/<category>/<name>.ts` (ä¸€éƒ¨ã¯ãƒˆãƒƒãƒ—į›´ä¸‹)。
### ä¸‰į‚šã‚ģット (`endpoints/ping.ts` å‚į…§)
å„ã‚¨ãƒŗãƒ‰ãƒã‚¤ãƒŗãƒˆãƒ•ã‚Ąã‚¤ãƒĢはäģĨ下ぎ 3 つを export する:
```ts
export const meta = {
tags: ['<tag>'],
requireCredential: true, // ぞたは false (åŋ…ず明į¤ē)
requireModerator: false, // åŋ…čρãĒら true
kind: 'read:account', // OAuth scope
res: {
type: 'object',
optional: false, nullable: false,
properties: { /* ... */ },
},
errors: {
sampleError: {
message: 'Sample error message.',
code: 'SAMPLE_ERROR',
id: 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx', // UUID v4 (`x`=hex, `y`=8/9/a/b)。`crypto.randomUUID()` ã§į”Ÿæˆã—ã€äģ–ã‚¨ãƒŗãƒ‰ãƒã‚¤ãƒŗãƒˆã¨é‡č¤‡ã•ã›ãĒい
},
},
} as const;
export const paramDef = {
type: 'object',
properties: { /* JSON Schema */ },
required: [],
} as const;
@Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
constructor(
// @Inject(DI.xxx) private xxxRepository: XxxRepository,
) {
super(meta, paramDef, async (ps, me) => {
// åŽŸčŖ…ã€‚ã‚¨ãƒŠãƒŧは throw new ApiError(meta.errors.xxx);
});
}
}
```
### æŗ¨æ„į‚š
- **å…Ŧ開 API エナãƒŧとしãĻクナイã‚ĸãƒŗãƒˆãĢčŋ”したいもぎは `throw new ApiError(meta.errors.<key>)` をäŊŋう**。`meta.errors` ãĢ列挙しãĻ `ApiError` でナップしãĒいと misskey-js 側ぎ型ãĢå‡ēず、ãƒŦã‚šãƒãƒŗã‚šã‚‚ 500 ãĢãĒる。
- 一斚で **æƒŗåŽšå¤–ãŽäž‹å¤– (DB 不整合 / ä¸‹åą¤ã‚ĩãƒŧビ゚ぎ bug į­‰) ã¯æĄã‚ŠæŊ°ã•ず再 throw する**。æ—ĸ存 endpoint も「期垅されるæĨ­å‹™ã‚¨ãƒŠãƒŧは `ApiError` ãĢ変換し、それäģĨ外は `throw err;` で再 throw」ぎä猿Žĩ構え (例: [`endpoints/i/pin.ts`](../../packages/backend/src/server/api/endpoints/i/pin.ts) ぎ `catch` ᝀ)ã€‚į”Ÿ `throw` を全éĸįρæ­ĸするとæœĒįŸĨ䞋外が 200 でæŊ°ã‚ŒãĻ debug 困雪ãĢãĒる。
- `meta.errors.<key>.id` は **UUID** åŊĸåŧã€‚æ–°čĻčŋŊ加時はäģ–ã‚¨ãƒŗãƒ‰ãƒã‚¤ãƒŗãƒˆã¨é‡č¤‡ã—ãĒいようįĸēčĒã™ã‚‹ã€‚
- `requireCredential` は `true` / `false` をåŋ…ず明į¤ēする。
- 新čĻã‚¨ãƒŗãƒ‰ãƒã‚¤ãƒŗãƒˆčŋŊ加垌は **`pnpm build-misskey-js-with-types`** ã‚’åŽŸčĄŒã™ã‚‹ (`misskey-js` ぎč‡Ēå‹•į”Ÿæˆãƒ•ã‚Ąã‚¤ãƒĢを更新)。
### ãƒĢãƒŧトį™ģ錞
ã‚¨ãƒŗãƒ‰ãƒã‚¤ãƒŗãƒˆã¯ **glob č‡Ē動収集されãĒい**。新čĻãƒ•ã‚Ąã‚¤ãƒĢを `endpoints/<category>/<name>.ts` ãĢįŊŽã„ただけでは API ãƒĢãƒŧãƒ†ã‚Ŗãƒŗã‚°ãĢ䚗らず、404 ãĢãĒる。`packages/backend/src/server/api/endpoint-list.ts` ãĢã‚ĸãƒĢãƒ•ã‚Ąãƒ™ãƒƒãƒˆé †ã§ 1 行čŋŊ加するぎがåŋ…é ˆ:
```ts
export * as '<category>/<name>' from './endpoints/<category>/<name>.js';
```
`EndpointsModule.ts` ãŒã“ãŽãƒ•ã‚Ąã‚¤ãƒĢぎ全エク゚ポãƒŧトを `Object.entries()` で反垊し、NestJS ぎ provider (`provide: 'ep:<path>'`) ã‚’į”Ÿæˆã™ã‚‹ã€‚čŠŗį´°ã¯ [.claude/skills/add-api-endpoint/SKILL.md](../skills/add-api-endpoint/SKILL.md) ぎ゚テップ 4 ã‚’å‚į…§ã€‚
## ãƒĸデãƒĢ / Repository
- ã‚¨ãƒŗãƒ†ã‚Ŗãƒ†ã‚Ŗ: `packages/backend/src/models/<Name>.ts` (`@Entity` + `@Column`)。
- DI įĩŒį”ąã§æŗ¨å…Ĩされる Repository をįĩŒį”ąã—ãĻã‚ĸクã‚ģ゚。
## Migration
čŠŗį´°æ‰‹é † (手書き斚åŧ = AGENTS.md §3 と整合):
> ã‚¨ãƒŗãƒ†ã‚Ŗãƒ†ã‚ŖåˇŽåˆ†ã‹ã‚‰ãŽč‡Ēå‹•į”Ÿæˆã‚„ `CREATE INDEX CONCURRENTLY` į­‰ãŽã‚Ēãƒ—ã‚ˇãƒ§ãƒŗã‚’äŊŋいたい場合は [.claude/skills/create-migration/SKILL.md](../skills/create-migration/SKILL.md) ぎ TypeORM CLI 手順をäŊŋう。手書き / CLI ãŠãĄã‚‰ã§ã‚‚ `check-migrations` (pending DDL 検å‡ē) ã•ãˆé€šã›ã°į­‰äžĄã€‚
1. **ã‚ŋイム゚ã‚ŋãƒŗãƒ—å–åž—**: `node -e "console.log(Date.now())"`
2. **ãƒ•ã‚Ąã‚¤ãƒĢ名**: `packages/backend/migration/{timestamp}-{PascalCaseName}.js` (æ‹Ąåŧĩ子は `.js`)
3. **雛åŊĸ**:
```js
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
export class PascalCaseName1234567890123 {
name = 'PascalCaseName1234567890123'
async up(queryRunner) {
// å‰é€˛ãƒžã‚¤ã‚°ãƒŦãƒŧã‚ˇãƒ§ãƒŗ
}
async down(queryRunner) {
// up を厌全ãĢåˇģきæˆģす
}
}
```
4. **検č¨ŧ**:
- `pnpm --filter backend check-migrations` (TypeORM schema builder で pending DDL を検å‡ēã™ã‚‹ã€‚ã‚¨ãƒŗãƒ†ã‚Ŗãƒ†ã‚Ŗã¨ migration ãŽä¸ä¸€č‡´ãŒæŽ‹ãŖãĻいるとここで非ã‚ŧロįĩ‚äē†ã™ã‚‹ã€‚åޟäŊ“は [scripts/check_migrations_clean.js](../../packages/backend/scripts/check_migrations_clean.js))
- `pnpm migrate` (ロãƒŧã‚ĢãƒĢ DB ãĢéŠį”¨)
- `pnpm revert` (ロãƒŧãƒĢバックįĸēčĒ)
5. **ã‚¨ãƒŗãƒ†ã‚Ŗãƒ†ã‚Ŗã¨ãŽæ•´åˆæ€§**: é–ĸé€Ŗã™ã‚‹ `src/models/*.ts` ぎ `@Column` / `@Entity` も同時ãĢ更新する。
> マãƒŧジ済ãŋ migration ãŽįˇ¨é›†ã¯ **įĩļ寞įρæ­ĸ** ([AGENTS.md §3](../../AGENTS.md#3-マãƒŧジ済ãŋ-migration-をįĩļ寞ãĢįˇ¨é›†ã—ãĒい))。
## テ゚ト
- Unit: `pnpm --filter backend test` (`vitest.config.unit.ts`)
- E2E: `pnpm --filter backend test:e2e` (`vitest.config.e2e.ts`)
- Federation: `pnpm --filter backend test:fed` (`vitest.config.fed.ts`)
- 配įŊŽ: `packages/backend/test/` 配下。

View File

@@ -1,76 +0,0 @@
# Frontend (`packages/frontend`) čĻį´„
Vue 3.5 + Vite + Storybook + Cypress E2E。
## ã‚ŗãƒŗãƒãƒŧãƒãƒŗãƒˆå‘Ŋ名
- å…ąæœ‰ / å†åˆŠį”¨ã‚ŗãƒŗãƒãƒŧãƒãƒŗãƒˆã¯ **`Mk` プãƒŦãƒ•ã‚Ŗãƒƒã‚¯ã‚š** (例: `MkButton.vue`, `MkInput.vue`, `MkAbuseReport.vue`)。
- ペãƒŧジ単äŊãŽã‚‚ぎは `packages/frontend/src/pages/` 配下ãĢįŊŽãã€‚
## SFC ゚ã‚ŋイãƒĢ
Composition API + `<script setup lang="ts">` をåŸēæœŦとする (Options API は新čĻå°Žå…ĨしãĒい)ã€‚åž‹åŽŖč¨€ã‚„ module ã‚šã‚ŗãƒŧプぎãƒĻãƒŧãƒ†ã‚ŖãƒĒãƒ†ã‚Ŗã‚’įŊŽããŸã„時は、setup ブロックと**äŊĩᔍ**するåŊĸでčŋŊ加ぎ `<script lang="ts">` ブロックをįŊŽã„ãĻ構わãĒい (例: [`MkInput.vue`](../../packages/frontend/src/components/MkInput.vue) は `SupportedTypes` 型をåˆĨãƒ–ãƒ­ãƒƒã‚¯ã§åŽŖč¨€ã—ãĻから setup を書いãĻいる)。SCSS は **CSS Modules** で書き、`<style lang="scss" module>` をäŊŋう:
```vue
<!--
SPDX-FileCopyrightText: syuilo and misskey-project
SPDX-License-Identifier: AGPL-3.0-only
-->
<template>
<div :class="$style.root">
<!-- ... -->
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
// ...
</script>
<style lang="scss" module>
.root {
/* ... */
}
</style>
```
## å›Ŋ際化 (i18n)
- 文字列ãƒĒテナãƒĢã‚’į›´æ›¸ãã—ãĒい。
- åŧ•æ•°ãĒし: `i18n.ts.<path>` ã§å‚į…§ã™ã‚‹ (例: `i18n.ts.deleted`)。
- åŧ•数あり: `i18n.tsx.<path>(...)` でé–ĸ数å‘ŧãŗå‡ēしする (例: `i18n.tsx.takeOverConfirm({ name })`)。
- 新čĻã‚­ãƒŧは **`locales/ja-JP.yml` ぎãŋ** ãĢčŋŊ加する (äģ–言čĒžã¯ Crowdin でč‡Ē動配äŋĄ)。
- `i18n` は `packages/frontend/src/i18n.ts` (ãžãŸã¯å…ąæœ‰ãƒĸジãƒĨãƒŧãƒĢ) から import する。
## ãƒĸãƒŧダãƒĢ / 通įŸĨ
- `os.ts` (`packages/frontend/src/os.ts`) įĩŒį”ąã§å‘ŧãļ。
- `os.alert(...)` / `os.confirm(...)` / `os.popup(...)` / `os.success(...)` ãĒお。
- ブナã‚Ļã‚ļ標æē–ぎ `window.alert()` / `window.confirm()` を **į›´æŽĨå‘ŧばãĒい**。
## ã‚ĸクã‚ģã‚ˇãƒ“ãƒĒãƒ†ã‚Ŗ (PR ãƒŦビãƒĨãƒŧã§æŒ‡æ‘˜ã•ã‚Œã‚„ã™ã„į‚š)
- クãƒĒãƒƒã‚¯ãƒãƒŗãƒ‰ãƒŠã‚’äģ˜ã‘ã‚‹ãĒら `<button>` をäŊŋうか、`role="button"` + `tabindex` をäģ˜ã‘る。
- フりãƒŧムčρᴠãĢは `<label>` ぞたは `aria-label` をäģ˜ã‘る。
- キãƒŧボãƒŧド操äŊœå¯čƒŊであること。
## Storybook
新čĻå…ąæœ‰ã‚ŗãƒŗãƒãƒŧãƒãƒŗãƒˆãĢは `<ComponentName>.stories.impl.ts` をäŊĩč¨­ã™ã‚‹ãŽãŒæ…Ŗįŋ’ (`MkButton.stories.impl.ts` į­‰ãŽäž‹å¤šæ•°)。
```bash
pnpm --filter frontend storybook-dev # localhost:6006
```
## ビãƒĢドãƒģ開į™ē
- 開į™ē: `pnpm dev` (ãƒĢãƒŧト) で backend + frontend が watch でįĢ‹ãĄä¸ŠãŒã‚‹ã€‚
- ビãƒĢド: `pnpm --filter frontend build`
- 型チェック: `pnpm --filter frontend typecheck` (vue-tsc)
- ESLint: `pnpm --filter frontend eslint`
## テ゚ト
- Unit (Vitest): `pnpm --filter frontend test`
- Cypress E2E: `pnpm e2e` (ãƒĢãƒŧトから; `start-server-and-test` でčĩˇå‹•)

View File

@@ -1,28 +0,0 @@
# 有劚化済 Claude Code ãƒ—ãƒŠã‚°ã‚¤ãƒŗ
`.claude/settings.json` で 14 ãƒ—ãƒŠã‚°ã‚¤ãƒŗãŒæœ‰åŠšåŒ–ã•ã‚ŒãĻã„ã‚‹ã€‚ãã‚Œãžã‚ŒãŽå…¸åž‹įš„ãĒåˆŠį”¨ã‚ˇãƒŧãƒŗã‚’ 1 čĄŒã§į¤ēす。
| ãƒ—ãƒŠã‚°ã‚¤ãƒŗ | ᔍ途 |
| --- | --- |
| `frontend-design` | UI ã‚ŗãƒŗãƒãƒŧãƒãƒŗãƒˆ / ペãƒŧã‚¸ãŽč¨­č¨ˆãƒģデã‚ļã‚¤ãƒŗäŊœæĨ­ (Vue 3 ᎍ集ãĢ有劚) |
| `superpowers` | TDDãƒģdebuggingãƒģbrainstormingãƒģplanning į­‰ãŽãƒĄã‚ŋ゚キãƒĢįž¤ |
| `context7` | OSS ドキãƒĨãƒĄãƒŗãƒˆãŽå–åž— (Vue 3, NestJS, TypeORM, Vitest į­‰) — č¨“įˇ´ãƒ‡ãƒŧã‚ŋãŽå¤ã•ã‚’čŖœã† |
| `code-review` | ã‚ŗãƒŧドãƒŦビãƒĨãƒŧ (`/code-review`) |
| `code-simplifier` | ã‚ŗãƒŧãƒ‰æ•´į† (`code-simplifier:code-simplifier` ã‚ĩブエãƒŧã‚¸ã‚§ãƒŗãƒˆįĩŒį”ą) |
| `github` | GitHub PR / Issue 操äŊœ (gh ベãƒŧã‚šã ãŒčŖœåŠŠã‚ŗãƒžãƒŗãƒ‰ã‚ã‚Š) |
| `skill-creator` | 新゚キãƒĢぎäŊœæˆãƒģ攚善ãƒģ評価 |
| `feature-dev` | 抟čƒŊ開į™ēã‚Ŧイド (`/feature-dev:feature-dev` / 内部ãĢ `code-architect` / `code-explorer` / `code-reviewer` ã‚ĩブエãƒŧã‚¸ã‚§ãƒŗãƒˆ) |
| `claude-md-management` | CLAUDE.md ぎäŊœæˆãƒģ攚善 (`/claude-md-management:revise-claude-md` / `claude-md-improver` エãƒŧã‚¸ã‚§ãƒŗãƒˆ) |
| `typescript-lsp` | TypeScript LSP 逪æē (åž‹æƒ…å ąã‚’æ´ģᔍ) |
| `security-guidance` | ã‚ģキãƒĨãƒĒãƒ†ã‚ŖãƒŦビãƒĨãƒŧ (`/security-review`) |
| `pr-review-toolkit` | PR ãƒŦビãƒĨãƒŧ一åŧã€‚ã‚ĩブエãƒŧã‚¸ã‚§ãƒŗãƒˆ: `code-reviewer` / `code-simplifier` / `comment-analyzer` / `pr-test-analyzer` / `silent-failure-hunter` / `type-design-analyzer` |
| `claude-code-setup` | Claude Code č‡Ē動化ã‚ģットã‚ĸãƒƒãƒ—ææĄˆ |
| `playwright` | ブナã‚Ļã‚ļč‡Ē動操äŊœ (ãƒ•ãƒ­ãƒŗãƒˆã‚¨ãƒŗãƒ‰å‹•äŊœįĸēčĒæ™‚ãĢæœ‰į”¨) |
## äŊŋい分けぎ指針
- **API é–ĸé€ŖãŽčĒŋæŸģ**: `context7` ã§å¯žčąĄãƒŠã‚¤ãƒ–ãƒŠãƒĒぎドキãƒĨãƒĄãƒŗãƒˆã‚’å–åž— → įˇ¨é›†ã€‚
- **PR äŊœæˆå‰**: `pr-review-toolkit` ぎ各エãƒŧã‚¸ã‚§ãƒŗãƒˆ (code-reviewer / silent-failure-hunter į­‰) をä¸Ļ列でčĩ°ã‚‰ã›ã‚‹ã€‚
- **新抟čƒŊãŽč¨­č¨ˆ**: `feature-dev` → brainstorming → åŽŸčŖ…ãŽæĩã‚Œã€‚
- **UI įĸēčĒ**: `playwright` で `pnpm dev` ぎį”ģéĸã‚’į›´æŽĨ操äŊœã€‚
- **将æĨčŋŊåŠ æ¤œč¨Ž**: PostgreSQL MCP — TypeORM + 342 migration ぎčĒŋæŸģåŠšįŽ‡åŒ–ã€‚read-only ロãƒŧãƒĢでį™ģéŒ˛ã—ã€æŽĨįļšå…ˆ (`misskey` DB) と樊限分é›ĸãĢæŗ¨æ„ã™ã‚‹ã€‚

View File

@@ -1,69 +0,0 @@
# テ゚ト構成
## Backend 全čˆŦぎ前提: `.config/test.yml`
backend ぎテ゚ト゚クãƒĒプト (`test` / `test:e2e` / `test:fed`) はすずãĻ内部で `cross-env NODE_ENV=test pnpm compile-config` ã‚’åŽŸčĄŒã—ã€`.config/test.yml` をčĒ­ãŋčžŧむ ([packages/backend/package.json](../../packages/backend/package.json), [packages/backend/scripts/compile_config.js](../../packages/backend/scripts/compile_config.js))。**æœĒäŊœæˆã ã¨ãƒ†ã‚šãƒˆč‡ĒäŊ“がčĩˇå‹•しãĒい。**
æœĒäŊœæˆãĒらäģĨ下を 1 å›žã ã‘æ‰‹å‹•ã‚ŗãƒ”ãƒŧする (ãŠãĄã‚‰ã§ã‚‚å¯):
```bash
ncp .github/misskey/test.yml .config/test.yml
# ぞたは
cp .github/misskey/test.yml .config/test.yml
```
誜čļŗ:
- ãƒĢãƒŧトぎ `pnpm start:test` (Cypress ᔍãĢテ゚トã‚ĩãƒŧバãƒŧをčĩˇå‹•ã™ã‚‹ã‚ŗãƒžãƒŗãƒ‰) をäŊŋうįĩŒčˇ¯ã§ã¯åŽŸčĄŒæ™‚ãĢ `ncp` でč‡Ēå‹•ã‚ŗãƒ”ãƒŧされる ([package.json](../../package.json))。それäģĨ外で backend ãƒ†ã‚šãƒˆã‚’į›´æŽĨčĩ°ã‚‰ã›ã‚‹æ™‚ã¯ä¸Šč¨˜ãŽæ‰‹å‹•ã‚ŗãƒ”ãƒŧがåŋ…čĻã€‚
- すでãĢ `.config/test.yml` があれば各テ゚ト゚クãƒĒプトぎ内部 `compile-config` で十分ãĒぎで、čŋŊ加で `pnpm --filter backend compile-config` を及くåŋ…čĻã¯ãĒい。
- `pnpm start:test` は backend e2e テ゚ト (`pnpm --filter backend test:e2e`) ぎ前提ではãĒい (ポãƒŧトįĢļ合ぎ元ãĢãĒるためäŊŋわãĒいこと)。
## Backend (Vitest 4, 3 č¨­åŽš)
| į¨ŽåˆĨ | č¨­åŽšãƒ•ã‚Ąã‚¤ãƒĢ | åŽŸčĄŒã‚ŗãƒžãƒŗãƒ‰ |
| --- | --- | --- |
| Unit | `packages/backend/vitest.config.unit.ts` | `pnpm --filter backend test` |
| E2E (HTTP / DB) | `packages/backend/vitest.config.e2e.ts` | `pnpm --filter backend test:e2e` |
| Federation | `packages/backend/vitest.config.fed.ts` | `pnpm --filter backend test:fed` |
- 配įŊŽ: `packages/backend/test/`
- äē‹å‰æē–備は [§Backend 全čˆŦぎ前提: `.config/test.yml`](#backend-全čˆŦぎ前提-configtestyml) ã‚’å‚į…§ã€‚
- ã‚ĢバãƒŦッジ: `pnpm --filter backend test-and-coverage`
## Frontend (Vitest)
```bash
pnpm --filter frontend test # 1 å›žåŽŸčĄŒ
pnpm --filter frontend test-and-coverage # ã‚ĢバãƒŦッジäģ˜ã
```
- ä¸ģãĒ配įŊŽ: `packages/frontend/test/*.test.ts` (例: `i18n.test.ts`, `theme.test.ts`, `is-birthday.test.ts`)。
- ビãƒĢドツãƒŧãƒĢ周りãĒãŠå¯žčąĄã‚ŗãƒŧãƒ‰ã¨éšŖæŽĨã•ã›ãŸæ–šãŒåˆ†ã‹ã‚Šã‚„ã™ã„ãƒ†ã‚šãƒˆã¯ã€ã‚ŗãƒŧãƒ‰ã¨åŒã˜ãƒ‡ã‚ŖãƒŦクトãƒĒãĢ `*.test.ts` としãĻįŊŽã (例: [`packages/frontend/lib/rollup-plugin-unwind-css-module-class-name.test.ts`](../../packages/frontend/lib/rollup-plugin-unwind-css-module-class-name.test.ts))。
- å…ąæœ‰ã‚ŗãƒŗãƒãƒŧãƒãƒŗãƒˆ (`MkX.vue`) ぎãƒĻãƒ‹ãƒƒãƒˆãƒ†ã‚šãƒˆã¯įžįŠļ少ãĒく、`*.spec.ts` / `__tests__/` åŊĸåŧã¯æŽĄį”¨ã—ãĻいãĒい (Storybook + Cypress でã‚Ģバãƒŧ)。
## E2E (Cypress)
ãƒĢãƒŧãƒˆã‹ã‚‰åŽŸčĄŒã™ã‚‹:
```bash
pnpm e2e # start:test ã‚ĩãƒŧバãƒŧをįĢ‹ãĻãĻ Cypress run
pnpm cy:open # å¯žčŠąįš„ãĢ開く
```
- č¨­åŽš: ãƒĢãƒŧト `cypress.config.ts`。テ゚トæœŦäŊ“は `cypress/` 配下。
## Storybook (frontend)
```bash
pnpm --filter frontend storybook-dev # http://localhost:6006
pnpm --filter frontend build-storybook # é™įš„ãƒ“ãƒĢド
```
- å„ã‚ŗãƒŗãƒãƒŧãƒãƒŗãƒˆæ¨ĒãĢ `*.stories.impl.ts` をäŊĩč¨­ã™ã‚‹æ…Ŗįŋ’ (例: `MkButton.stories.impl.ts`)。
- Chromatic (`pnpm --filter frontend chromatic`) でčĻ–čĻšå›žå¸°ãƒã‚§ãƒƒã‚¯ã€‚
## ロãƒŧã‚ĢãƒĢ DB / Redis (テ゚トãƒģ開į™ēå…ąé€š)
```bash
docker compose -f compose.local-db.yml up -d
```

View File

@@ -1,18 +0,0 @@
{
"enabledPlugins": {
"frontend-design@claude-plugins-official": true,
"superpowers@claude-plugins-official": true,
"context7@claude-plugins-official": true,
"code-review@claude-plugins-official": true,
"code-simplifier@claude-plugins-official": true,
"github@claude-plugins-official": true,
"skill-creator@claude-plugins-official": true,
"feature-dev@claude-plugins-official": true,
"claude-md-management@claude-plugins-official": true,
"typescript-lsp@claude-plugins-official": true,
"security-guidance@claude-plugins-official": true,
"pr-review-toolkit@claude-plugins-official": true,
"claude-code-setup@claude-plugins-official": true,
"playwright@claude-plugins-official": true
}
}

View File

@@ -1,33 +0,0 @@
# `.claude/skills/` — プロジェクトå›ē有ぎã‚Ģ゚ã‚ŋム゚キãƒĢ
Misskey å›ēæœ‰ãŽįš°ã‚Ščŋ”しã‚ŋ゚クを Claude ãĢ゚ムãƒŧã‚ēãĢåŽŸčĄŒã•ã›ã‚‹ãŸã‚ãŽ **ã‚Ģ゚ã‚ŋム゚キãƒĢ** を `.claude/skills/<name>/SKILL.md` åŊĸåŧã§é…įŊŽã™ã‚‹ã€‚
frontmatter (`name` + `description`) は、Claude が **č‡Ē動で゚キãƒĢをå‘ŧãŗå‡ēすか判断する** 唯一ぎ手がかりãĢãĒる。`description` ãĢã¯į”¨é€”ã‚’å…ˇäŊ“įš„ã‹ã¤įļ˛įž…įš„ãĢ書く (å‹•čŠž + å¯žčąĄ + トãƒĒã‚ŦãƒŧæĄäģļ)。
## åŽŸčŖ…æ¸ˆã‚šã‚­ãƒĢ
### Misskey å›ē有 (æœŦãƒĒポジトãƒĒ向け書きčĩˇã“し)
| ゚キãƒĢ名 | åŊšå‰˛ | å„Ē先åēĻ |
| --- | --- | --- |
| [create-migration](create-migration/SKILL.md) | TypeORM CLI (`migration:generate` / `migration:create`) でマイグãƒŦãƒŧã‚ˇãƒ§ãƒŗã‚’į”Ÿæˆã—ã€SPDX / up-down / `check-migrations` ぞでčĒ˜å°Ž | é̘ (342 æ—ĸ存 / čĻį´„åŽŗã—ã„) |
| [add-api-endpoint](add-api-endpoint/SKILL.md) | NestJS DI + meta/paramDef čĻį´„ã§ API ã‚¨ãƒŗãƒ‰ãƒã‚¤ãƒŗãƒˆčŋŊ加。`endpoint-list.ts` į™ģéŒ˛ã¨ `misskey-js` å†į”Ÿæˆã‚’åĢむ | é̘ |
| [add-i18n-key](add-i18n-key/SKILL.md) | `locales/ja-JP.yml` ぎãŋįˇ¨é›†ã™ã‚‹čŖœåŠŠã€‚åž‹ã¯ `packages/i18n` がč‡Ēå‹•å†į”Ÿæˆ | 中 |
| [add-mk-component](add-mk-component/SKILL.md) | `Mk*` å‘Ŋ名 + SPDX (HTML) + SCSS module + `*.stories.impl.ts` äŊĩč¨­ãŽ Vue ã‚ŗãƒŗãƒãƒŧãƒãƒŗãƒˆã‚’ä¸€æ‹Ŧã‚šã‚­ãƒŖãƒ•ã‚ŠãƒŧãƒĢド | 中 |
### ECC (everything-claude-code) į”ąæĨ — MIT ã‚ģãƒŦã‚¯ãƒˆã‚¤ãƒŗãƒãƒŧト
[.claude/THIRD_PARTY_LICENSES.md](../THIRD_PARTY_LICENSES.md) §1 ãĢå‡ē典ãƒģæ”šå¤‰ãƒĄãƒĸãƒģMIT å…¨æ–‡ã‚’é›†į´„ã€‚
| ゚キãƒĢ名 | åŊšå‰˛ | å„Ē先åēĻ |
| --- | --- | --- |
| [context-budget](context-budget/SKILL.md) | agents / skills / MCP / CLAUDE.md ぎ token overhead をčĻ‹ãˆã‚‹åŒ–ã—ã€č‚Ĩå¤§ã‚ŗãƒŗãƒãƒŧãƒãƒŗãƒˆã‚’æ¤œå‡ē | 中 |
č¨­č¨ˆæ–šé‡: `create-migration` は手動ぎ `Date.now()` å‘Ŋ名ではãĒく TypeORM å…Ŧåŧ CLI (`migration:generate` / `migration:create`) ã‚’æŽĄį”¨ã€‚Storybook ãƒ•ã‚Ąã‚¤ãƒĢ名は `*.stories.impl.ts` čĻį´„ãĢæē–拠する。
## 新čĻã‚šã‚­ãƒĢをčŋŊ加する場合
- `.claude/skills/<name>/SKILL.md` ãĢ YAML frontmatter (`name` + `description`) とæœŦ文 Markdown を書く。
- `disable-model-invocation: true` はäģ˜ã‘ãĒい (auto-invoke させたいため)。
- ä¸ģčĻå‚į…§ãƒ•ã‚Ąã‚¤ãƒĢへぎãƒĒãƒŗã‚¯ã¯ã€ãƒĒポジトãƒĒãƒĢãƒŧãƒˆã‹ã‚‰ãŽį›¸å¯žãƒ‘ã‚š (例: `../../packages/backend/...`) でč˛ŧる。įĩļ寞パ゚は contributor ぎホãƒŧãƒ ãƒ‡ã‚ŖãƒŦクトãƒĒ䞝存ãĢãĒるぎでäŊŋわãĒい。
- 厌成したらこぎ README ãŽčĄ¨ãĢも 1 行čŋŊ加する。

View File

@@ -1,253 +0,0 @@
---
name: add-api-endpoint
description: Misskey ぎ REST API ã‚¨ãƒŗãƒ‰ãƒã‚¤ãƒŗãƒˆ (/api/<category>/<name>) を NestJS DI + meta/paramDef čĻį´„ã§čŋŊåŠ ã™ã‚‹ã€‚ãƒãƒƒã‚¯ã‚¨ãƒŗãƒ‰ãĢ新しい API ãƒĢãƒŧトをčļŗã™æ™‚ãĢåŋ…ずäŊŋう。endpoint-list.ts へぎ手動į™ģéŒ˛ã€e2e テ゚ト、misskey-js å†į”Ÿæˆã€CHANGELOG ãžã§ãŽä¸€é€ŖãŽæ‰‹é †ã‚’åĢむ。
---
# Misskey API ã‚¨ãƒŗãƒ‰ãƒã‚¤ãƒŗãƒˆčŋŊ加゚キãƒĢ
`packages/backend/src/server/api/endpoints/<category>/<name>.ts` ãĢ新čĻã‚¨ãƒŗãƒ‰ãƒã‚¤ãƒŗãƒˆã‚’čŋŊ加するためぎワãƒŧクフロãƒŧ。**手順 4 (endpoint-list.ts į™ģ錞) をåŋ˜ã‚Œã‚‹ã¨ 404 ãĢãĒる** į‚šãĢæœ€å¤§ãŽæŗ¨æ„ã‚’æ‰•ã†ã€‚
## 最重čρäē‹åޟ (čĻ‹čŊã¨ã™ã¨åŖŠã‚Œã‚‹)
1. ã‚¨ãƒŗãƒ‰ãƒã‚¤ãƒŗãƒˆã¯ **glob č‡Ē動収集されãĒい**。[packages/backend/src/server/api/endpoint-list.ts](../../../packages/backend/src/server/api/endpoint-list.ts) へぎ 1 行čŋŊ加がåŋ…須。
2. `meta` / `paramDef` を変えたら **misskey-js ãŽå†į”ŸæˆãŒåŋ…é ˆ**。`pnpm build-misskey-js-with-types` をåŋ˜ã‚Œã‚‹ã¨ CI ぎ `check-misskey-js-autogen` でåŋ…ずčŊãĄã‚‹ã€‚
3. `meta.errors` ぎ各 `id` は **UUID**ã€‚é‡č¤‡ã•ã›ãĒい (æ—ĸ存全 UUID ã¨čĄįǁįĸēčĒ)。
## ゚テップ 1: ãƒ•ã‚Ąã‚¤ãƒĢ配įŊŽã¨ SPDX
`packages/backend/src/server/api/endpoints/<category>/<name>.ts` ãĢ新čĻäŊœæˆã™ã‚‹ã€‚`<category>` は抟čƒŊ領域 (例: `notes`, `users`, `admin/announcements`)。
冒頭ãĢ SPDX ヘッダãƒŧをåŋ…ずäģ˜ã‘ã‚‹:
```ts
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
```
## ゚テップ 2: æœ€å°ãƒ†ãƒŗãƒ—ãƒŦãƒŧト (ã‚ˇãƒŗãƒ—ãƒĢ read įŗģ)
[endpoints/ping.ts](../../../packages/backend/src/server/api/endpoints/ping.ts) をベãƒŧ゚ãĢ書く。čĒč¨ŧ不čρãƒģãƒ‘ãƒŠãƒĄãƒŧã‚ŋãĒしãƒģ小さãĒãƒŦã‚šãƒãƒŗã‚šãŽäž‹:
```ts
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js';
export const meta = {
tags: ['<tag>'],
requireCredential: false,
res: {
type: 'object',
optional: false, nullable: false,
properties: {
// ...
},
},
} as const;
export const paramDef = {
type: 'object',
properties: {},
required: [],
} as const;
@Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
constructor(
) {
super(meta, paramDef, async (ps, me) => {
// åŽŸčŖ…
});
}
}
```
## ゚テップ 3: čĒč¨ŧäģ˜ã / DI / errors をåĢã‚€ãƒ†ãƒŗãƒ—ãƒŦãƒŧト
[endpoints/notes/create.ts](../../../packages/backend/src/server/api/endpoints/notes/create.ts) ã‚’å‚į…§ã™ã‚‹ã€‚čĻį‚š:
```ts
import { Inject, Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js';
import { ApiError } from '@/server/api/error.js';
import { DI } from '@/di-symbols.js';
// import ms from 'ms'; // limit.duration ãĢ ms('1hour') į­‰ã‚’æ¸Ąã™ã¨ã (default import)
export const meta = {
tags: ['notes'],
requireCredential: true, // čĒč¨ŧåŋ…é ˆãĒら true
prohibitMoved: false, // moved user を拒åĻするか
kind: 'write:notes', // OAuth scope (requireCredential 時ãĢåŋ…é ˆ)
limit: {
duration: 3600000, // ms('1hour')
max: 300,
},
errors: {
noSuchNote: {
message: 'No such note.',
code: 'NO_SUCH_NOTE',
id: 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx', // ★ UUID v4 をåŋ…ãšį”Ÿæˆ (`x`=hex, `y`=8/9/a/b)。下ぎ「UUID į”Ÿæˆã€ã‚’å‚į…§
},
},
res: {
type: 'object',
optional: false, nullable: false,
ref: 'Note', // packed entity ãĢ揃える場合
},
} as const;
export const paramDef = {
type: 'object',
properties: {
noteId: { type: 'string', format: 'misskey:id' },
},
required: ['noteId'],
} as const;
@Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
constructor(
@Inject(DI.notesRepository)
private notesRepository: NotesRepository,
) {
super(meta, paramDef, async (ps, me) => {
const note = await this.notesRepository.findOneBy({ id: ps.noteId });
if (note == null) throw new ApiError(meta.errors.noSuchNote);
// åŽŸčŖ…
});
}
}
```
### meta ãƒ•ã‚ŖãƒŧãƒĢド旊čĻ‹čĄ¨
| ãƒ•ã‚ŖãƒŧãƒĢド | ᔍ途 |
|---|---|
| `tags` | OpenAPI ã‚ŋグ (抟čƒŊ領域) |
| `requireCredential` | čĒč¨ŧåŋ…須か |
| `requireModerator` / `requireAdmin` | 樊限åˆļ限 |
| `prohibitMoved` | ã‚ĸã‚Ģã‚Ļãƒŗãƒˆį§ģčĄŒæ¸ˆãƒĻãƒŧã‚ļãƒŧを拒åĻ |
| `kind` | OAuth scope (`read:notes` / `write:notes` į­‰)。`requireCredential: true` 時åŋ…é ˆ |
| `limit` | ãƒŦãƒŧトåˆļ限 (`{ duration, max, key?, minInterval? }`) |
| `errors` | エナãƒŧåŽšįžŠã€‚å„čρᴠãĢ `message` / `code` / `id` (UUID v4) åŋ…é ˆ |
| `res` | JSON Schema or `ref: '<EntityName>'` (packed entity å‚į…§) |
| `requireFile` | ãƒ•ã‚Ąã‚¤ãƒĢã‚ĸップロãƒŧドåŋ…é ˆ |
| `secure` | secure cookie åŋ…čρ |
| `allowGet` | GET ãƒĄã‚Ŋãƒƒãƒ‰č¨ąå¯ |
| `cacheSec` | ãƒŦã‚šãƒãƒŗã‚šã‚­ãƒŖãƒƒã‚ˇãƒĨį§’æ•° |
| `description` | OpenAPI čĒŦ明 |
čŠŗį´°ã¯ [endpoints.ts](../../../packages/backend/src/server/api/endpoints.ts) ãŽåž‹åŽšįžŠ (lines 11-125) ã‚’å‚į…§ã€‚
### paramDef ãŽį‰šæŽŠãƒ•ã‚Šãƒŧマット
JSON Schema (AJV) ベãƒŧ゚だが、Misskey æ‹ĄåŧĩをäŊŋえる:
- `format: 'misskey:id'` — ID 文字列バãƒĒデãƒŧã‚ˇãƒ§ãƒŗ
- `allOf` / `anyOf` / `oneOf` — č¤‡åˆæĄäģļ
- `default` — デフりãƒĢト値
čŠŗį´°ã¯ [endpoint-base.ts](../../../packages/backend/src/server/api/endpoint-base.ts) ã‚’å‚į…§ã€‚
### エナãƒŧ throw
**「å…Ŧ開 API エナãƒŧとしãĻ API クナイã‚ĸãƒŗãƒˆãĢčŋ”したいもぎ」はåŋ…ず `throw new ApiError(meta.errors.<key>)` をäŊŋう**。`meta.errors` ãĢ列挙した上で `ApiError` でナップしãĒいと、misskey-js å´ãŽåž‹æƒ…å ąãĢå‡ēず、ãƒŦã‚šãƒãƒŗã‚šã‚‚ 500 ãĢãĒる。įŦŦ 2 åŧ•数でčŋŊåŠ æƒ…å ąã‚’æ¸Ąã›ã‚‹:
```ts
throw new ApiError(meta.errors.invalidParam, { reason: 'too short' });
```
一斚で、**æƒŗåŽšå¤–ãŽäž‹å¤– (DB 不整合 / ä¸‹åą¤ã‚ĩãƒŧビ゚ぎ bug ãĒお) ã‚’æĄã‚ŠæŊ°ã™ãŸã‚ãĢ `try/catch` で `ApiError` ãĢ変換するぎはéŋける**。æ—ĸ存 endpoint も「期垅されるæĨ­å‹™ã‚¨ãƒŠãƒŧは `ApiError` ãĢ変換し、それäģĨ外は `throw err;` で再 throw する」というä猿Žĩ構えãĢãĒãŖãĻいる。`packages/backend/src/server/api/endpoints/notes/create.ts` ぎ `catch` ᝀ (æœĢ尞ぎ `throw err;`) ã‚’å‚į…§ã€‚į”ŸãŽ `throw` を全éĸįρæ­ĸするとæœĒįŸĨ䞋外も 200 でæŊ°ã‚ŒãĻ debug ãŒå›°é›ŖãĢãĒã‚‹ãŽã§ã€ã“ãŽãƒãƒŠãƒŗã‚šã‚’äŋã¤ã€‚
čŠŗį´°ã¯ [error.ts](../../../packages/backend/src/server/api/error.ts) ぎ `ApiError` ã‚¯ãƒŠã‚šã‚’å‚į…§ã€‚
### UUID į”Ÿæˆ
```bash
node -e "console.log(crypto.randomUUID())"
```
そぎ UUID がäģ–ãŽã‚¨ãƒŗãƒ‰ãƒã‚¤ãƒŗãƒˆãŽ `id` ã¨čĄįĒã—ãĻいãĒいかåŋ…ずįĸēčĒ:
```bash
grep -r "id: '<į”Ÿæˆã—ãŸ UUID>'" packages/backend/src/server/api/endpoints/
```
## ゚テップ 4: ★åŋ…é ˆ — endpoint-list.ts ãĢį™ģ錞
[packages/backend/src/server/api/endpoint-list.ts](../../../packages/backend/src/server/api/endpoint-list.ts) ぎ同ã‚ĢテゴãƒĒæœĢå°žãĢ 1 行čŋŊ加するīŧˆæ—ĸ存ぎä¸Ļãŗã‚’å´Šã•ãĒいīŧ‰:
```ts
export * as '<category>/<name>' from './endpoints/<category>/<name>.js';
```
ãƒ•ã‚Ąã‚¤ãƒĢå†’é ­ãŽã‚ŗãƒĄãƒŗãƒˆ (`When you add new endpoint, you should add it to this file.`) ぎ通り、こぎãƒĒ゚トが API ãƒĢãƒŧãƒ†ã‚Ŗãƒŗã‚°ãŽå˜ä¸€ãŽįœŸåŽŸã€‚**åŋ˜ã‚Œã‚‹ã¨ 404**。
`EndpointsModule.ts` ãŒã“ãŽãƒ•ã‚Ąã‚¤ãƒĢぎ全エク゚ポãƒŧトを `Object.entries()` で反垊し、NestJS provider (`provide: 'ep:<path>'`) ã‚’į”Ÿæˆã™ã‚‹ã€‚
## ゚テップ 5: e2e テ゚トčŋŊ加
[packages/backend/test/e2e/endpoints.ts](../../../packages/backend/test/e2e/endpoints.ts) ãĢ寞åŋœã™ã‚‹ `describe` / `test` をčŋŊ加する。`api()` ヘãƒĢパãƒŧで及く:
```ts
describe('<category>/<name>', () => {
test('æ­Ŗå¸¸įŗģ', async () => {
const res = await api('<category>/<name>', { /* params */ }, alice);
assert.strictEqual(res.status, 200);
});
});
```
åŽŸčĄŒ: `pnpm --filter backend test:e2e`
## ゚テップ 6: misskey-js å†į”Ÿæˆ (★åŋ…é ˆ)
`meta` / `paramDef` / `res` を変えたらåŋ…ãšåŽŸčĄŒã™ã‚‹:
```bash
pnpm build-misskey-js-with-types
```
これでäģĨ下が更新される:
- `packages/backend/built/api.json` (OpenAPI spec)
- `packages/misskey-js/generator/api.json`
- `packages/misskey-js/src/autogen/*.ts` (TypeScript 型)
PR ãĢ `packages/misskey-js/src/autogen/` é…ä¸‹ãŽåˇŽåˆ†ãŒåĢぞれãĻいãĒいと、CI ぎ `check-misskey-js-autogen` でčŊãĄã‚‹ã€‚
## ゚テップ 7: Lint と typecheck
```bash
pnpm --filter backend lint
```
(typecheck = `tsgo --noEmit` / ESLint = `eslint`)
## ゚テップ 8: CHANGELOG
ãƒĻãƒŧã‚ļãƒŧåŊąéŸŋがある (新抟čƒŊ / æ—ĸ存挙動変更) ãĒら、`CHANGELOG.md` ぎ `## Unreleased` → `### Server` ãĢ 1 行čŋŊ加する ([AGENTS.md §CHANGELOG](../../../AGENTS.md#changelog) å‚į…§):
```
- Feat: /api/<category>/<name> をčŋŊ加
```
ᴔឋãĒãƒĒãƒ•ã‚Ąã‚¯ã‚ŋã‚„å†…éƒ¨į”¨ãĒら不čĻã€‚
## å‚į…§ãƒ•ã‚Ąã‚¤ãƒĢ
- [endpoints.ts (meta/paramDef åž‹åŽšįžŠ)](../../../packages/backend/src/server/api/endpoints.ts)
- [endpoint-base.ts (Endpoint åŸēåē•クナ゚)](../../../packages/backend/src/server/api/endpoint-base.ts)
- [endpoint-list.ts (★ ここãĢį™ģ錞)](../../../packages/backend/src/server/api/endpoint-list.ts)
- [error.ts (ApiError)](../../../packages/backend/src/server/api/error.ts)
- [endpoints/ping.ts (最小䞋)](../../../packages/backend/src/server/api/endpoints/ping.ts)
- [endpoints/notes/create.ts (DI + errors ぎ典型)](../../../packages/backend/src/server/api/endpoints/notes/create.ts)
- [test/e2e/endpoints.ts (テ゚ト䞋)](../../../packages/backend/test/e2e/endpoints.ts)
- [scripts/generate_api_json.js (misskey-js į”Ÿæˆå…ƒ)](../../../packages/backend/scripts/generate_api_json.js)

View File

@@ -1,117 +0,0 @@
---
name: add-i18n-key
description: Misskey ぎ i18n キãƒŧをčŋŊ加ãƒģäŋŽæ­Ŗã™ã‚‹ã€‚locales/ja-JP.yml ぎãŋįˇ¨é›†å¯čƒŊで、äģ–言čĒžãƒ•ã‚Ąã‚¤ãƒĢ (en-US.yml į­‰ 39 言čĒž) は Crowdin ぎč‡Ē動配äŋĄå…ˆãŽãŸã‚įĩļ寞ãĢč§ĻらãĒい。型は packages/i18n が ja-JP.yml からč‡Ēå‹•å†į”Ÿæˆã™ã‚‹ã€‚frontend からは i18n.ts.<key> ぞたは i18n.tsx.<key>(...) ã§å‚į…§ã™ã‚‹ã€‚
---
# Misskey i18n キãƒŧčŋŊ加゚キãƒĢ
UI æ–‡č¨€ãŽčŋŊ加ãƒģå¤‰æ›´ã‚’čĄŒã†éš›ãŽčĻį´„ã€‚**æ‰‹å‹•įˇ¨é›†ã—ãĻč‰¯ã„ãŽã¯ `locales/ja-JP.yml` ぎãŋ。**
## 大前提 (įĩļ寞 NG)
- **`locales/<lang>.yml` (ja-JP.yml äģĨ外) ãŽįˇ¨é›†ã¯įρæ­ĸ**。これらは Crowdin ぎč‡Ē動配äŋĄå…ˆã§ã€æ‰‹å‹•įˇ¨é›†ã™ã‚‹ã¨æŦĄãŽåŒæœŸã§ä¸Šæ›¸ãå–Ēå¤ąã™ã‚‹ ([locales/README.md](../../../locales/README.md), [crowdin.yml](../../../crowdin.yml))。
- 文字列ãƒĒテナãƒĢを SFC ãĢį›´æ›¸ãã—ãĒい (`<span>こんãĢãĄã¯</span>` į­‰)。åŋ…ず `i18n.ts.<key>` をįĩŒį”ąã™ã‚‹ã€‚
- æ—ĸ存キãƒŧãŽį ´åŖŠįš„ãƒĒネãƒŧムは Crowdin įŋģč¨ŗčŗ‡į”Ŗã‚‚é“é€Ŗã‚ŒãĢãĒるぎで慎重ãĢ。čŋŊ加ãƒģ攚名äŊĩᔍ (新キãƒŧčŋŊ加 → į§ģ行 → 旧キãƒŧ削除) ã‚’æ¤œč¨Žã™ã‚‹ã€‚
## ゚テップ 1: ja-JP.yml ãĢキãƒŧをčŋŊ加
[locales/ja-JP.yml](../../../locales/ja-JP.yml) ã‚’įˇ¨é›†ã™ã‚‹ã€‚YAML ãŽéšŽåą¤æ§‹é€ ã‚’įļ­æŒã—、é–ĸé€Ŗã™ã‚‹ã‚ģã‚¯ã‚ˇãƒ§ãƒŗãĢ配įŊŽã™ã‚‹:
```yaml
# トップãƒŦベãƒĢå˜į´”ã‚­ãƒŧ
save: "äŋå­˜"
# ネ゚トしたã‚ĢテゴãƒĒ (ã‚ĸãƒŗãƒ€ãƒŧã‚šã‚ŗã‚ĸæŽĨé ­čžžã¯å†…éƒ¨ã‚ĢテゴãƒĒ)
_settings:
general: "全čˆŦ"
appearance: "外čĻŗ"
# ãƒ‘ãƒŠãƒĄãƒŧã‚ŋäģ˜ã (å˜į´”ãĒプãƒŦãƒŧ゚ホãƒĢダįŊŽæ›)
# ICU MessageFormat ぎ plural / select / number / date ãĒおは非寞åŋœ
# äŊŋえるぎは `{name}` ぎようãĒå˜į´”ãĒįŊŽæ›ãŽãŋ
greeting: "こんãĢãĄã¯ã€{name}さん"
```
### å‘Ŋ名ぎおäŊœæŗ•
- å˜į´”ã‚­ãƒŧ: lowerCamelCase (例: `saveChanges`, `confirmDelete`)。
- ã‚ĢテゴãƒĒ: ã‚ĸãƒŗãƒ€ãƒŧã‚šã‚ŗã‚ĸæŽĨ頭辞 (例: `_settings`, `_abuseUserReport`)。
- æ—ĸ存ã‚ģã‚¯ã‚ˇãƒ§ãƒŗå†…ãĢįŊŽãå ´åˆã¯ã‚ĸãƒĢãƒ•ã‚Ąãƒ™ãƒƒãƒˆé †ã‚’įļ­æŒã™ã‚‹ (新ã‚ģã‚¯ã‚ˇãƒ§ãƒŗå…¨äŊ“ã‚’æœĢå°žãĢčŋŊ加するぎは可)。
## ゚テップ 2: åž‹åŽšįžŠãŽč‡Ēå‹•å†į”Ÿæˆ
`packages/i18n/build.ts` が `ja-JP.yml` ã‚’č§Ŗæžã—ã€TypeScript ã‚¤ãƒŗã‚ŋãƒŧフェãƒŧ゚を [packages/i18n/src/autogen/locale.ts](../../../packages/i18n/src/autogen/locale.ts) ãĢå‡ē力する。
### č‡Ē動 (推åĨ¨)
`pnpm dev` åŽŸčĄŒä¸­ãĒら、`packages/i18n` ぎ watch ゚クãƒĒプトが yml ぎ変更を検įŸĨしãĻč‡Ēå‹•å†į”Ÿæˆã™ã‚‹ã€‚
### 手動
```bash
pnpm --filter i18n generate
```
原äŊ“は `tsx scripts/generateLocaleInterface.ts`。
### å¤ąæ•—ãƒ‘ã‚ŋãƒŧãƒŗ
ã“ã‚Œã‚’åŽŸčĄŒã›ãšãĢ frontend 側で `i18n.ts.<newKey>` ã‚’å‚į…§ã™ã‚‹ã¨ã€`Locale` ã‚¤ãƒŗã‚ŋãƒŧフェãƒŧ゚ãĢčŋŊ加されãĻいãĒいため、typecheck で「Property '<newKey>' does not exist on type 'Locale'」というエナãƒŧãĢãĒる。`pnpm --filter frontend lint` でį™ēčĻšã™ã‚‹ã€‚
## ゚テップ 3: frontend ã§ãŽå‚į…§
```ts
import { i18n } from '@/i18n.js';
```
| ᔍ途 | 書き斚 |
|---|---|
| å˜į´”æ–‡å­—åˆ— | `i18n.ts.save` |
| ネ゚ト | `i18n.ts._settings.general` |
| ãƒ‘ãƒŠãƒĄãƒŧã‚ŋäģ˜ã | `i18n.tsx.greeting({ name: userName })` |
| Vue ãƒ†ãƒŗãƒ—ãƒŦãƒŧト内 | `{{ i18n.ts.save }}` / `{{ i18n.tsx.greeting({ name }) }}` |
`i18n.ts` は型äģ˜ãæ–‡å­—列、`i18n.tsx` は MessageFormat é–ĸ数。
## ゚テップ 4: 検č¨ŧ
```bash
# i18n ãƒ‘ãƒƒã‚ąãƒŧã‚¸ãŽåž‹å†į”Ÿæˆ + typecheck
pnpm --filter i18n lint
# frontend で新キãƒŧå‚į…§įŽ‡æ‰€ãŽåž‹ãƒã‚§ãƒƒã‚¯
pnpm --filter frontend lint
```
## 例: 「ノãƒŧトを削除しぞすかīŧŸã€įĸēčĒãƒ€ã‚¤ã‚ĸログをčŋŊ加する
1. `locales/ja-JP.yml`:
```yaml
_notes:
deleteConfirm: "こぎノãƒŧトを削除しぞすかīŧŸ"
```
2. `pnpm --filter i18n generate` (ぞたは `pnpm dev` で watch 中)
3. SFC:
```vue
<script setup lang="ts">
import { i18n } from '@/i18n.js';
import * as os from '@/os.js';
async function onDelete() {
const { canceled } = await os.confirm({
type: 'warning',
text: i18n.ts._notes.deleteConfirm,
});
if (canceled) return;
// 削除å‡Ļᐆ
}
</script>
```
## å‚į…§ãƒ•ã‚Ąã‚¤ãƒĢ
- [locales/README.md (★ įˇ¨é›†ãƒãƒĒã‚ˇãƒŧæ šæ‹ )](../../../locales/README.md)
- [locales/ja-JP.yml](../../../locales/ja-JP.yml)
- [packages/i18n/build.ts](../../../packages/i18n/build.ts)
- [packages/i18n/src/autogen/locale.ts (į”Ÿæˆį‰Š)](../../../packages/i18n/src/autogen/locale.ts)
- [packages/frontend/src/i18n.ts](../../../packages/frontend/src/i18n.ts)

View File

@@ -1,174 +0,0 @@
---
name: add-mk-component
description: Misskey ãƒ•ãƒ­ãƒŗãƒˆã‚¨ãƒŗãƒ‰ãŽæ–°čĻ Vue 3 ã‚ŗãƒŗãƒãƒŧãƒãƒŗãƒˆã‚’čŋŊ加する。Mk* å‘Ŋ名 / SPDX (HTML ã‚ŗãƒĄãƒŗãƒˆ) / <script setup lang="ts"> / <style lang="scss" module> / *.stories.impl.ts äŊĩč¨­ãŽčĻį´„ã‚’ãžã¨ã‚ãĻéŠį”¨ã™ã‚‹ã€‚æ–°ã—ã„å…ąæœ‰ UI ã‚ŗãƒŗãƒãƒŧãƒãƒŗãƒˆã‚’ packages/frontend/src/components/ ãĢäŊœã‚‹æ™‚ãĢäŊŋう。
---
# Misskey Vue ã‚ŗãƒŗãƒãƒŧãƒãƒŗãƒˆčŋŊ加゚キãƒĢ
`packages/frontend/src/components/` ãĢæ–°ã—ã„å…ąæœ‰ã‚ŗãƒŗãƒãƒŧãƒãƒŗãƒˆã‚’čŋŊ加するためぎčĻį´„ã€‚
## 大前提
- å…ąæœ‰ / å†åˆŠį”¨ã‚ŗãƒŗãƒãƒŧãƒãƒŗãƒˆã¯ **åŋ…ず `Mk` プãƒŦãƒ•ã‚Ŗãƒƒã‚¯ã‚š** (例: `MkButton`, `MkInput`)。ペãƒŧジå›ē有部品ãĒお `Mk` プãƒŦãƒ•ã‚Ŗãƒƒã‚¯ã‚šã§ãĒいもぎは原則 `pages/` 側ãĢįŊŽãã€‚
- 新čĻã§ã¯ `<style lang="scss" module>` (CSS Modules) をæ—ĸ厚とする。古い `scoped` åŊĸåŧãŒæˇˇåœ¨ã—ãĻいるが、新čĻã§ã¯äŊŋわãĒい。
- 文字列ãƒĒテナãƒĢãŽį›´æ›¸ãã¯įρæ­ĸã€‚æ–‡č¨€ã¯åŋ…ず `i18n.ts.<key>` įĩŒį”ąã§å‚į…§ã™ã‚‹ (新キãƒŧは `add-i18n-key` ゚キãƒĢã‚’å‚į…§)。
- `alert()` / `confirm()` / `window.prompt()` はäŊŋわãĒい。`os.alert` / `os.confirm` / `os.popup` ãĒおをäŊŋう。
## ゚テップ 1: ãƒ•ã‚Ąã‚¤ãƒĢ配įŊŽ
`packages/frontend/src/components/Mk<Name>.vue` ãĢ新čĻäŊœæˆã™ã‚‹ã€‚
゚トãƒŧãƒĒãƒŧがåŋ…čρ (= ãģãŧ常ãĢåŋ…čρ) ãĒã‚‰ã€åŒéšŽåą¤ãĢ `Mk<Name>.stories.impl.ts` もäŊœã‚‹ã€‚Storybook ぎčĻį´„ã¯ `*.stories.impl.ts` ã§ã‚ãŖãĻ、`*.stories.ts` ではãĒい。
## ゚テップ 2: SPDX ヘッダãƒŧ (HTML ã‚ŗãƒĄãƒŗãƒˆåŊĸåŧ)
`.vue` ãƒ•ã‚Ąã‚¤ãƒĢ冒頭ãĢåŋ…é ˆ:
```html
<!--
SPDX-FileCopyrightText: syuilo and misskey-project
SPDX-License-Identifier: AGPL-3.0-only
-->
```
`/* ... */` (TS / JS åŊĸåŧ) ではãĒく **HTML ã‚ŗãƒĄãƒŗãƒˆ** で書くこと。æ—ĸ存ぎ `.vue` ãƒ•ã‚Ąã‚¤ãƒĢがすずãĻ HTML ã‚ŗãƒĄãƒŗãƒˆåŊĸåŧã‚’äŊŋãŖãĻおり、SFC ぎ先頭としãĻč‡Ēį„ļãĒåŊĸåŧãĢįĩąä¸€ã™ã‚‹ãŸã‚ (CI ぎ `spdx` ã‚¸ãƒ§ãƒ–ã¯ã‚ŗãƒĄãƒŗãƒˆåŊĸåŧã§ã¯ãĒく SPDX æ–‡å­—åˆ—ãŽæœ‰į„ĄãŽãŋを検æŸģする)。
## ゚テップ 3: æœ€å°ãƒ†ãƒŗãƒ—ãƒŦãƒŧト
[MkInfo.vue](../../../packages/frontend/src/components/MkInfo.vue) をベãƒŧ゚ãĢする (ã‚ˇãƒŗãƒ—ãƒĢãĒ襨į¤ēã‚ŗãƒŗãƒãƒŧãƒãƒŗãƒˆ):
```vue
<!--
SPDX-FileCopyrightText: syuilo and misskey-project
SPDX-License-Identifier: AGPL-3.0-only
-->
<template>
<div :class="$style.root">
<slot></slot>
</div>
</template>
<script lang="ts" setup>
const props = defineProps<{
variant?: 'primary' | 'secondary';
}>();
const emit = defineEmits<{
(ev: 'click'): void;
}>();
</script>
<style lang="scss" module>
.root {
padding: 12px 14px;
border-radius: var(--MI-radius);
background: var(--MI_THEME-panel);
}
</style>
```
### čĻį´„ãƒã‚¤ãƒŗãƒˆ
| é …į›Ž | čĻį´„ |
|---|---|
| `<script>` | `<script lang="ts" setup>`ã€‚åž‹ãƒ‘ãƒŠãƒĄãƒŧã‚ŋがåŋ…čρãĒら `generic="T extends ..."` をäģ˜ã‘ã‚‹ ([MkInput.vue å‚į…§](../../../packages/frontend/src/components/MkInput.vue)) |
| `defineProps` / `defineEmits` | **type-only** (`<{ ... }>`) åŊĸåŧã€‚runtime ぎ object åŊĸåŧã¯äŊŋわãĒい |
| `<style>` | `lang="scss" module` をæ—ĸåŽšã€‚ã‚¯ãƒŠã‚šå‚į…§ã¯ `:class="$style.foo"` |
| CSS 変数 | `var(--MI_THEME-...)` (テãƒŧマ) / `var(--MI-radius)` (UI å…ąé€š) — ハãƒŧãƒ‰ã‚ŗãƒŧドしãĒい |
| ã‚ĸã‚¤ã‚ŗãƒŗ | Tabler icons ぎクナ゚ (`<i class="ti ti-info-circle">`) をäŊŋう |
## ゚テップ 4: i18n と os ãŽåˆŠį”¨
```vue
<script lang="ts" setup>
import { i18n } from '@/i18n.js';
import * as os from '@/os.js';
async function onClick() {
const { canceled } = await os.confirm({
type: 'warning',
text: i18n.ts._notes.deleteConfirm,
});
if (canceled) return;
os.toast(i18n.ts.deleted);
}
</script>
```
### `os` ぎä¸ģãĒヘãƒĢパãƒŧ (čŠŗį´°ã¯ [os.ts](../../../packages/frontend/src/os.ts))
| é–ĸ数 | ᔍ途 |
|---|---|
| `os.alert({ type, title?, text })` | 単斚向ã‚ĸナãƒŧト |
| `os.confirm({ type, title, text })` | yes/no įĸēčĒ (`{ canceled }` をčŋ”す) |
| `os.toast(message)` | 一時通įŸĨ |
| `os.popup(component, props, handlers)` | äģģæ„ã‚ŗãƒŗãƒãƒŧãƒãƒŗãƒˆãŽéžåŒæœŸãƒãƒƒãƒ—ã‚ĸップ |
| `os.popupMenu(items, anchor?)` | ã‚ŗãƒŗãƒ†ã‚­ã‚šãƒˆãƒĄãƒ‹ãƒĨãƒŧ |
| `os.form(title, fields)` | フりãƒŧムダイã‚ĸログ |
| `os.apiWithDialog(endpoint, data)` | API å‘ŧå‡ēし + エナãƒŧ時ダイã‚ĸãƒ­ã‚°čĄ¨į¤ē |
## ゚テップ 5: Storybook ゚トãƒŧãƒĒãƒŧäŊĩ設
[MkButton.stories.impl.ts](../../../packages/frontend/src/components/MkButton.stories.impl.ts) を雛åŊĸとしãĻå‚č€ƒãĢする。`.stories.impl.ts` も `packages/frontend/src/` 配下ぎ `.ts` ãƒ•ã‚Ąã‚¤ãƒĢãĒぎで [AGENTS.md §1 SPDX ヘッダãƒŧåŋ…é ˆ](../../../AGENTS.md#1-spdx-ヘッダãƒŧåŋ…é ˆ) ãŽå¯žčąĄã§ã‚ã‚Šã€å†’é ­ãĢ SPDX ヘッダãƒŧをåŋ…ずäģ˜ã‘ã‚‹ (HTML ã‚ŗãƒĄãƒŗãƒˆåŊĸåŧã§ã¯ãĒく `/* */` åŊĸåŧ)。åŊĸåŧ (äģĨ下ぎ `MkXxx` ã¯åŽŸéš›ãŽã‚ŗãƒŗãƒãƒŧãƒãƒŗãƒˆåãĢįŊŽæ›ã™ã‚‹):
```ts
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
/* eslint-disable @typescript-eslint/explicit-function-return-type */
/* eslint-disable import/no-default-export */
import type { StoryObj } from '@storybook/vue3';
import MkXxx from './MkXxx.vue';
export const Default = {
render(args) {
return {
components: { MkXxx },
setup() {
return { args };
},
template: '<MkXxx v-bind="args">slot content</MkXxx>',
};
},
args: {
variant: 'primary',
},
parameters: {
layout: 'centered',
},
} satisfies StoryObj<typeof MkXxx>;
```
`Vue` SFC は default export ãĒぎで、`import MkXxx from './MkXxx.vue';` ぎようãĢ名前äģ˜ã import ではãĒく default import ã§æ›¸ãã€‚åŽŸčĄŒįĸēčĒã¯ `pnpm --filter frontend storybook-dev`。
## ゚テップ 6: Lint と typecheck
```bash
pnpm --filter frontend lint
```
(typecheck = vue-tsc į­‰ã€ESLint = `@misskey-dev/eslint-plugin` åĢむ)
ESLint --fix ã‚’ãƒ”ãƒŗãƒã‚¤ãƒŗãƒˆã§:
```bash
pnpm exec eslint --fix packages/frontend/src/components/Mk<Name>.vue
```
## ゚テップ 7: æ—ĸå­˜ã‚ŗãƒŗãƒãƒŧãƒãƒŗãƒˆã¨ãŽæ•´åˆæ€§įĸēčĒ
- äŧŧãŸį”¨é€”ãŽæ—ĸ存 `Mk*` ã‚ŗãƒŗãƒãƒŧãƒãƒŗãƒˆã‚’å‚č€ƒãĢ、゚ã‚ŋイãƒĢやプロップå‘Ŋ名を揃える。
- `_button` / `_panel` / `_selectable` ãĒおぎ **å…ąé€š utility class** (グロãƒŧバãƒĢ゚ã‚ŋイãƒĢãĢある) をæ´ģį”¨ã§ãã‚‹ã‹įĸēčĒã™ã‚‹ã€‚
- 大きãĒ抟čƒŊãĒら、Storybook stories で各バãƒĒエãƒŧã‚ˇãƒ§ãƒŗã‚’įļ˛įž…する。
## å‚į…§ãƒ•ã‚Ąã‚¤ãƒĢ
- [MkInfo.vue (ã‚ˇãƒŗãƒ—ãƒĢ例)](../../../packages/frontend/src/components/MkInfo.vue)
- [MkButton.vue (æąŽį”¨ãƒœã‚ŋãƒŗäž‹)](../../../packages/frontend/src/components/MkButton.vue)
- [MkInput.vue (generics + 多抟čƒŊ例)](../../../packages/frontend/src/components/MkInput.vue)
- [MkButton.stories.impl.ts (Storybook 雛åŊĸ)](../../../packages/frontend/src/components/MkButton.stories.impl.ts)
- [packages/frontend/src/os.ts](../../../packages/frontend/src/os.ts)
- [packages/frontend/src/i18n.ts](../../../packages/frontend/src/i18n.ts)

View File

@@ -1,148 +0,0 @@
---
name: context-budget
description: Claude Code ã‚ģãƒƒã‚ˇãƒ§ãƒŗãŽã‚ŗãƒŗãƒ†ã‚­ã‚šãƒˆįĒ“æļˆč˛ģを agents/skills/MCP/rules/CLAUDE.md ごとãĢčĻ‹ãˆã‚‹åŒ–ã—ã€č‚Ĩå¤§åŒ–ã¨å†—é•ˇã‚ŗãƒŗãƒãƒŧãƒãƒŗãƒˆã‚’æ¤œå‡ēしãĻį¯€į´„å€™čŖœã‚’æį¤ēする。"ã‚ŗãƒŗãƒ†ã‚­ã‚šãƒˆæļˆč˛ģをčĻ‹ã›ãĻ"、"context budget"、"context audit"、"トãƒŧã‚¯ãƒŗå†…č¨ŗ"、"これäģĨ上 MCP å…ĨるīŧŸ" į­‰ãŽį™ēčŠąã§čĩˇå‹•する。
---
<!--
SPDX-License-Identifier: MIT
SPDX-FileCopyrightText: 2026 Affaan Mustafa and everything-claude-code contributors
å‡ē典 (upstream): https://github.com/affaan-m/everything-claude-code (v2.0.0-rc.1)
upstream path: skills/context-budget/SKILL.md
upstream origin frontmatter: ECC
upstream license: MIT — https://github.com/affaan-m/everything-claude-code/blob/main/LICENSE
project-level notice: see .claude/THIRD_PARTY_LICENSES.md (Misskey 内ã‚ĩãƒŧドパãƒŧãƒ†ã‚Ŗä¸€čϧ + MIT 全文)
Imported into Misskey .claude/ on 2026-05-10 as a standalone copy (no dependency on the ECC plugin runtime). description was rewritten in Japanese and a "Misskey å›ēæœ‰ãƒĄãƒĸ" section was appended; body content remains MIT-licensed.
note: Misskey ぎ skills/agents 数は少ãĒいぎで、MCP / CLAUDE.md / ãƒ—ãƒŠã‚°ã‚¤ãƒŗį”ąæĨぎ overhead ãŒæ”¯é…įš„ãĢãĒã‚Šã‚„ã™ã„į‚šãĢį•™æ„ã€‚
-->
# Context Budget
ã‚ģãƒƒã‚ˇãƒ§ãƒŗå†…ãĢčĒ­ãŋčžŧãžã‚Œã‚‹ã‚ŗãƒŗãƒãƒŧãƒãƒŗãƒˆ (agents / skills / rules / MCP servers / CLAUDE.md) ぎ token overhead を分析し、įŠēき context ã‚’å›žåžŠã™ã‚‹å…ˇäŊ“į­–ã‚’æį¤ēする。
## äŊŋう場éĸ
- ã‚ģãƒƒã‚ˇãƒ§ãƒŗãŒé‡ã„ãƒģå‡ē力品čŗĒがčŊãĄãĻきた感čĻšãŒã‚ã‚‹
- į›´čŋ‘で skills / agents / MCP server を多数čŋŊ加した
- 掋りぎ context headroom をįŸĨりたい
- čŋŊåŠ ã‚ŗãƒŗãƒãƒŧãƒãƒŗãƒˆã‚’å…Ĩれる前ãĢįŠēきをįĸēčĒã—ãŸã„
- 「context-budget」「token å†…č¨ŗã€į­‰ãŽã‚­ãƒŧワãƒŧドでãƒĻãƒŧã‚ļãƒŧが明į¤ēįš„ãĢčρčĢ‹ã—ãŸæ™‚ (Misskey ãƒĒポジトãƒĒãĢã¯ã“ãŽåå‰ãŽã‚šãƒŠãƒƒã‚ˇãƒĨã‚ŗãƒžãƒŗãƒ‰ã¯į™ģéŒ˛ã—ãĻいãĒい — æœŦ skill は名前 / description マッチで auto-invoke ã•ã‚Œã‚‹æƒŗåŽšã€‚åŽŸčŖ…æ¸ˆãŽ slash command 一čĻ§ã¯ [.claude/commands/](../../commands/) ã‚’å‚į…§)
## äģ•įĩ„ãŋ
### Phase 1: Inventory
å„ã‚ŗãƒŗãƒãƒŧãƒãƒŗãƒˆã‚’čĩ°æŸģしãĻ token を推厚する。
**Agents** (`.claude/agents/*.md`)
- čĄŒæ•°ã¨ãƒˆãƒŧã‚¯ãƒŗæ•° (`words × 1.3`) ã‚’č¨ˆįŽ—
- frontmatter `description` ãŽé•ˇã•ã‚’æŠŊå‡ē
- フナグ: 200 行čļ… (重い)、description 30 word čļ… (frontmatter č‚Ĩ大)
**Skills** (`.claude/skills/*/SKILL.md`)
- SKILL.md ごとãĢ token ã‚’č¨ˆįŽ—
- フナグ: 400 行čļ…
- `.agents/skills/` į­‰ãŽé‡č¤‡ã‚ŗãƒ”ãƒŧは除外
**Rules** (ãƒĒポジトãƒĒãƒĢãƒŧトぎ `AGENTS.md` + `.claude/` から `@-import` ã•ã‚Œã‚‹ãƒ•ã‚Ąã‚¤ãƒĢ)
- ãƒ•ã‚Ąã‚¤ãƒĢ単äŊã§ token č¨ˆįŽ—
- フナグ: 100 行čļ…
- åŒä¸€č¨€čĒžãƒĸジãƒĨãƒŧãƒĢå†…ãŽå†…åŽšé‡č¤‡ã‚’æ¤œå‡ē
**MCP Servers** (`.mcp.json` ぞたは有劚 MCP č¨­åŽš)
- server æ•°ã¨įˇ tool 数
- schema overhead をツãƒŧãƒĢあたり ~500 token でčĻ‹įŠã‚‚ã‚‹
- フナグ: 20 tool čļ…ぎã‚ĩãƒŧバãƒŧ、`gh` / `git` / `npm` į­‰ãŽ CLI ã‚’å˜į´”ãƒŠãƒƒãƒ—ã—ãŸã ã‘ãŽã‚ĩãƒŧバãƒŧ
**CLAUDE.md** (project + user-level)
- ãƒ•ã‚Ąã‚¤ãƒĢごとãĢ token ã‚’č¨ˆįŽ—
- フナグ: 合荈 300 行čļ…
### Phase 2: Classify
| ãƒã‚ąãƒƒãƒˆ | 判厚åŸēæē– | čĄŒå‹• |
|--------------------|-------------------------------------------------------------|-----------------------------------|
| **Always needed** | CLAUDE.md ã‹ã‚‰å‚į…§ã•ã‚ŒãĻいる / æœ‰åŠšã‚ŗãƒžãƒŗãƒ‰ãŽčŖ / įžãƒ—ãƒ­ã‚¸ã‚§ã‚¯ãƒˆã¨ä¸€č‡´ | įļ­æŒ |
| **Sometimes needed** | ãƒ‰ãƒĄã‚¤ãƒŗäžå­˜ (例: 言čĒžãƒ‘ã‚ŋãƒŧãƒŗ)、CLAUDE.md å‚į…§ãĒし | ã‚Ēãƒŗãƒ‡ãƒžãƒŗãƒ‰æœ‰åŠšåŒ–ã‚’æ¤œč¨Ž |
| **Rarely needed** | ã‚ŗãƒžãƒŗãƒ‰å‚į…§ãĒã—ã€å†…åŽšé‡č¤‡ã€æ˜ŽįĸēãĒᔍ途ãĒし | 削除ぞたは lazy-load |
### Phase 3: Detect Issues
- **Bloated agent description** — frontmatter description が 30 word čļ…だと、Task ツãƒŧãƒĢčĩˇå‹•ãŽãŸãŗãĢ毎回ロãƒŧドされる
- **Heavy agents** — 200 行čļ…は Task ツãƒŧãƒĢぎ context ã‚’æ¯Žå›žč†¨ã‚‰ãžã›ã‚‹
- **Redundant components** — agent ãƒ­ã‚¸ãƒƒã‚¯ã‚’é‡č¤‡ã™ã‚‹ skill、CLAUDE.md ã¨é‡č¤‡ã™ã‚‹ rule
- **MCP over-subscription** — 10 server čļ…、ぞたは CLI äģŖį”¨å¯čƒŊãĒã‚ĩãƒŧバãƒŧ
- **CLAUDE.md bloat** — 冗镎čĒŦ明、古いã‚ģã‚¯ã‚ˇãƒ§ãƒŗã€rule ãĢį§ģすずき指į¤ē
### Phase 4: Report
```
Context Budget Report
═══════════════════════════════════════
Total estimated overhead: ~XX,XXX tokens
Context model: <įžåœ¨ãƒĸデãƒĢ名> (<window>K window) ← 例: Claude Opus 4.7 (1M), Claude Sonnet (200K)
Effective available context: ~XXX,XXX tokens (XX%)
Component Breakdown:
┌─────────────────â”Ŧ────────â”Ŧ───────────┐
│ Component │ Count │ Tokens │
├─────────────────â”ŧ────────â”ŧ───────────┤
│ Agents │ N │ ~X,XXX │
│ Skills │ N │ ~X,XXX │
│ Rules │ N │ ~X,XXX │
│ MCP tools │ N │ ~XX,XXX │
│ CLAUDE.md │ N │ ~X,XXX │
└─────────────────┴────────┴───────────┘
WARNING: Issues Found (N):
[token į¯€į´„é‡ãŽé™é †]
Top 3 Optimizations:
1. [action] → save ~X,XXX tokens
2. [action] → save ~X,XXX tokens
3. [action] → save ~X,XXX tokens
Potential savings: ~XX,XXX tokens (XX% of current overhead)
```
verbose mode ではさらãĢãƒ•ã‚Ąã‚¤ãƒĢごとぎ token å†…č¨ŗã€æœ€é‡ãƒ•ã‚Ąã‚¤ãƒĢãŽčĄŒå˜äŊãƒ–ãƒŦãƒŧクダã‚Ļãƒŗã€é‡č¤‡čĄŒãŽå¯žæ¯”ã€MCP tool 一čϧ + tool ごとぎ schema ã‚ĩイã‚ē推厚をå‡ēす。
## 例
**åŸēæœŦᛪæŸģ**
```
User: ã‚ŗãƒŗãƒ†ã‚­ã‚šãƒˆæļˆč˛ģをčĻ‹ã›ãĻ
Skill: 16 agents (12,400 tokens), 28 skills (6,200), 87 MCP tools (43,500), 2 CLAUDE.md (1,200)
Flags: 重い agent 3 個、CLI äģŖį”¨å¯čƒŊãĒ MCP 3 個
Top saving: MCP 3 個削除 → -27,500 tokens (overhead ぎ 47% 削減)
```
**Verbose**
```
User: トãƒŧã‚¯ãƒŗå†…č¨ŗã‚’ãƒ•ã‚Ąã‚¤ãƒĢ単äŊã§
Skill: 䏊荘ãƒŦポãƒŧトãĢ加えãĻ、planner.md (213 lines, 1,840 tokens) ぎようãĒ
per-file čĄŒå†…č¨ŗã€MCP tool ごとぎã‚ĩイã‚ē、rule ãŽé‡č¤‡čĄŒã‚’ side-by-side ã§čĄ¨į¤ē
```
**čŋŊ加前チェック**
```
User: MCP server を 5 個čŋŊ加したいが、įŠēきあるīŧŸ
Skill: įžįŠļ 33% → 5 server (≈ 50 tools) čŋŊ加で +25,000 tokens → 45% ãĢ到達
推åĨ¨: CLI äģŖį”¨å¯čƒŊãĒ server 2 個を先ãĢ外しãĻ 40% äģĨ下をįļ­æŒ
```
## ãƒ™ã‚šãƒˆãƒ—ãƒŠã‚¯ãƒ†ã‚Ŗã‚š
- **トãƒŧã‚¯ãƒŗæŽ¨åŽš**: prose は `words × 1.3`、code ä¸ģäŊ“は `chars / 4`
- **MCP は最大ぎãƒŦバãƒŧ**: tool あたり ~500 token、30-tool server ã˛ã¨ã¤ã§å…¨ skill より大きい
- **agent description は常時ロãƒŧド**: å‘ŧばれãĒい agent でも description は毎 Task 投å…Ĩ
- **verbose は debug ᔍ**: 晎æŽĩはäŊŋわãĒい
- **å¤‰æ›´åžŒã¯į›ŖæŸģ**: agent/skill/MCP čŋŊåŠ į›´åžŒãĢčĩ°ã‚‰ã›ãĻ creep を旊期į™ēčĻ‹
## Misskey å›ēæœ‰ãƒĄãƒĸ
- Misskey は MCP server をプロジェクトで明į¤ēį™ģéŒ˛ã—ãĻいãĒいため (`.mcp.json` 不在)ã€įžįŠļ overhead ぎ支配項は CLAUDE.md とå…Ŧåŧãƒ—ãƒŠã‚°ã‚¤ãƒŗįž¤ãŽ skills / agents description である。
- ECC ãƒ—ãƒŠã‚°ã‚¤ãƒŗãŒãƒĻãƒŧã‚ļãƒŧã‚šã‚ŗãƒŧプで `installed_plugins.json` ãĢ存在するため、プロジェクトで `enabledPlugins` ãĢčŋŊ加しãĻいãĒくãĻも system reminder ãĢ 200+ skill ãŒįžã‚Œã‚‹ã€‚ã“ã‚Œã‚‰ã¯ description ãŒįŸ­ã„ãŽã§å€‹åˆĨ overhead ã¯å°ã•ã„ãŒã€åˆč¨ˆå€¤ãŽįĸēčĒãĢæœŦ skill をäŊŋう。

View File

@@ -1,156 +0,0 @@
---
name: create-migration
description: Misskey ぎ TypeORM マイグãƒŦãƒŧã‚ˇãƒ§ãƒŗã‚’å…Ŧåŧ CLI (migration:generate / migration:create) ã§æ­Ŗã—ãį”Ÿæˆã—ã€SPDX ヘッダãƒŧäģ˜ä¸Žãƒģup/down 整合ãƒģcheck-migrations įĸēčĒãžã§čĒ˜å°Žã™ã‚‹ã€‚ã‚¨ãƒŗãƒ†ã‚Ŗãƒ†ã‚ŖãŽã‚šã‚­ãƒŧマ変更をåĢむあらゆる DB 変更、ぞたは手書き SQL ãĢよるデãƒŧã‚ŋį§ģčĄŒãŒåŋ…čρãĒ時ãĢäŊŋį”¨ã™ã‚‹ã€‚
---
# Misskey マイグãƒŦãƒŧã‚ˇãƒ§ãƒŗäŊœæˆã‚šã‚­ãƒĢ
`packages/backend/migration/` ãĢ新čĻ TypeORM マイグãƒŦãƒŧã‚ˇãƒ§ãƒŗã‚’čŋŊ加するためぎワãƒŧクフロãƒŧ。
## 大前提 (įĩļ寞 NG)
- **æ—ĸãĢマãƒŧジ済ãŋ (develop / master) ぎマイグãƒŦãƒŧã‚ˇãƒ§ãƒŗãƒ•ã‚Ąã‚¤ãƒĢã‚’įˇ¨é›†ã—ãĒい** ([AGENTS.md §3](../../../AGENTS.md#3-マãƒŧジ済ãŋ-migration-をįĩļ寞ãĢįˇ¨é›†ã—ãĒい))。æœŦį•ĒåąĨæ­´ãŽæ”šå¤‰ã¯æˇąåˆģãĒデãƒŧã‚ŋ不整合をåŧ•きčĩˇã“す。゚キãƒŧマ変更は **常ãĢ新しいã‚ŋイム゚ã‚ŋãƒŗãƒ—ã§æ–°čĻãƒ•ã‚Ąã‚¤ãƒĢ** をäŊœã‚‹ã€‚
- ãƒ•ã‚Ąã‚¤ãƒĢ名ぎã‚ŋイム゚ã‚ŋãƒŗãƒ—éƒ¨åˆ†ã‚’åžŒã‹ã‚‰æ›¸ãæ›ãˆãĒい (順åēãŒåŖŠã‚Œã‚‹)。
> äŊœã‚Šæ–šã¯ AGENTS.md §3 ぎ「`Date.now()` で UNIX ms を取垗 → `{ms}-{PascalName}.js` を手書き」が最äŊŽãƒŠã‚¤ãƒŗã€‚ã‚¨ãƒŗãƒ†ã‚Ŗãƒ†ã‚ŖåˇŽåˆ†ã‹ã‚‰č‡Ēå‹•į”Ÿæˆã—ãŸã„ (= TypeORM ぎ `migration:generate` をäŊŋう) 場合はæœŦ skill ぎ手順ãĢ垓う。**ãŠãĄã‚‰ã§ã‚‚æ§‹ã‚ãĒい**ãŒã€ã‚¨ãƒŗãƒ†ã‚Ŗãƒ†ã‚Ŗå¤‰æ›´ã‚’äŧ´ã†æ™‚は CLI įĩŒį”ąãŽãģうが取りæŧã‚ŒãŒæ¸›ã‚‹ãŽã§æŽ¨åĨ¨ã€‚
## ゚テップ 1: ãŠãĄã‚‰ãŽæ–šåŧã‚’äŊŋうかæąēめる
| įŠļæŗ | æ–šåŧ |
|---|---|
| ã‚¨ãƒŗãƒ†ã‚Ŗãƒ†ã‚Ŗ (`packages/backend/src/models/*.ts`) を `@Column` / `@Index` / `@Entity` į­‰ã§å…ˆãĢå¤‰æ›´ã—ã€åˇŽåˆ†ã‹ã‚‰č‡Ēå‹•į”Ÿæˆã—ãŸã„ | `typeorm migration:generate` (æœŦ skill ぎ手順) |
| 手書き SQL / デãƒŧã‚ŋį§ģ行 / `CREATE INDEX CONCURRENTLY` ãĒãŠã€ã‚¨ãƒŗãƒ†ã‚Ŗãƒ†ã‚ŖåˇŽåˆ†ã§ã¯čĄ¨įžã§ããĒい変更 | `typeorm migration:create` でįŠē雛åŊĸをäŊœã‚‹ã‹ã€`migrate-new` command で手書き雛åŊĸをäŊœã‚‹ |
| 列čŋŊ加 1 æœŦぎようãĒ小čĻæ¨Ąå¤‰æ›´ã§ã€æ—ĸå­˜ãƒ•ã‚Ąã‚¤ãƒĢã‚’ã‚ŗãƒ”ãƒŧした斚が速い | AGENTS.md §3 ぎ手順 (`Date.now()` + 手書き) でよい |
čŋˇãŖãŸã‚‰ **ãžãšã‚¨ãƒŗãƒ†ã‚Ŗãƒ†ã‚Ŗã‚’å¤‰æ›´ → `migration:generate`** が原則。æ—ĸ存 342 ãƒ•ã‚Ąã‚¤ãƒĢぎãģãŧすずãĻが `queryRunner.query(\`SQL...\`)` ぎ raw SQL ãĒぎで、CLI å‡ē力でも手書きでも゚ã‚ŋイãƒĢは揃う。
## ゚テップ 2: CLI åŽŸčĄŒ
ãƒĢãƒŧãƒˆãƒ‡ã‚ŖãƒŦクトãƒĒからäģĨä¸‹ã‚’åŽŸčĄŒã™ã‚‹ã€‚`<PascalName>` ã¯å¤‰æ›´å†…åŽšã‚’čĄ¨ã™ PascalCase (例: `AddBirthdayIndex`, `AddCategoryToAvatarDecorations`)。
### 2-A. ã‚¨ãƒŗãƒ†ã‚Ŗãƒ†ã‚ŖåˇŽåˆ†ã‹ã‚‰į”Ÿæˆ
[CONTRIBUTING.md §MigrationäŊœæˆæ–šæŗ•](../../../CONTRIBUTING.md#migrationäŊœæˆæ–šæŗ•) ãĢ記čŧ‰ãŽåŸēæœŦåŊĸ:
```bash
# packages/backend ãƒ‡ã‚ŖãƒŦクトãƒĒã§åŽŸčĄŒã™ã‚‹å ´åˆ (CONTRIBUTING.md 記čŧ‰åŊĸåŧ)
pnpm dlx typeorm migration:generate -d ormconfig.js -o --esm <PascalName>
```
**ãƒĒポジトãƒĒãƒĢãƒŧãƒˆã‹ã‚‰åŽŸčĄŒã™ã‚‹å ´åˆ** (AI がäŊŋう推åĨ¨åŊĸåŧã€‚`pnpm --filter backend exec` をäŊŋうと backend ぎ TypeORM バãƒŧã‚¸ãƒ§ãƒŗã¨ä¸€č‡´ã™ã‚‹ãŸã‚įĸē原):
```bash
pnpm --filter backend exec typeorm migration:generate -d ormconfig.js -o --esm migration/<PascalName>
```
> **`--esm` ãĢついãĻ**: `-o` / `--outputJs` は「TS ではãĒく JS をå‡ē力する」ã‚Ēãƒ—ã‚ˇãƒ§ãƒŗã€`--esm` は「ESM åŊĸåŧ (`export class ...`) でå‡ē力する」ã‚Ēãƒ—ã‚ˇãƒ§ãƒŗã€‚Misskey ぎæ—ĸ存 migration はすずãĻ ESM JS であるため **ä¸Ąæ–šãŒåŋ…é ˆ**。`--esm` ã‚’įœį•Ĩすると CommonJS åŊĸåŧãŽ JS ãŒį”Ÿæˆã•ã‚Œã‚šã‚ŋイãƒĢが揃わãĒい。
äē‹å‰æē–å‚™:
- `pnpm build-pre` ã‚’åŽŸčĄŒã—ãĻ `built/meta.json` ã‚’į”Ÿæˆã™ã‚‹ (`loadConfig()` が `built/meta.json` をåŋ…須とするため。`pnpm build` 済ãŋであれば不čρ)。
- `.config/default.yml` が存在すること (ãĒければ `.config/example.yml` ã‚’å‚č€ƒãĢäŊœæˆã™ã‚‹)。
- `pnpm --filter backend compile-config` ã‚’åŽŸčĄŒã—ãĻ `built/.config.json` ã‚’į”Ÿæˆã™ã‚‹ (`ormconfig.js` が `loadConfig()` įĩŒį”ąã§åŋ…須とする。æœĒåŽŸčĄŒã ã¨ "Compiled configuration file not found." エナãƒŧãĢãĒる)。
- `pnpm --filter backend build` ã§ã‚¨ãƒŗãƒ†ã‚Ŗãƒ†ã‚Ŗã‚’æœ€æ–°ãƒ“ãƒĢド (CLI は `built/` をčĒ­ã‚€)。
- ロãƒŧã‚ĢãƒĢ DB をčĩˇå‹•する (`docker compose -f compose.local-db.yml up -d`)。
### 2-B. įŠēぎ手書きマイグãƒŦãƒŧã‚ˇãƒ§ãƒŗ
```bash
pnpm --filter backend exec typeorm migration:create -o --esm migration/<PascalName>
```
ロãƒŧã‚ĢãƒĢ DB ぎčĩˇå‹•とビãƒĢドは不čĻã€‚įŠēぎ `up` / `down` ã ã‘ãŒį”Ÿæˆã•ã‚Œã‚‹ã€‚
> `-o --esm` を **åŋ…ずäģ˜ã‘ã‚‹**ã€‚ã“ã‚ŒãŒį„Ąã„ã¨ `<UnixMs>-<PascalName>.ts` (CommonJS / TS å‡ē力) ãŒį”Ÿæˆã•ã‚Œã‚‹ãŒã€Misskey ぎ `ormconfig.js` は `migration/*.js` だけをčĒ­ãŋ、æ—ĸ存ぎäģ– migration も全ãĻ `export class ... { async up(queryRunner) {...} }` ぎ ESM JS åŊĸåŧãĒぎで、垌で手äŊœæĨ­ã§ `.ts → .js` ãƒĒネãƒŧム + `import { MigrationInterface }` 削除 + `class ... implements MigrationInterface` 削除をしãĒいとčĩ°ã‚‰ãĒい。`-o --esm` をäģ˜ã‘ればそぎぞぞ `.js` ESM でå‡ēるぎで、垌å‡Ļį†ã¯ SPDX ヘッダãƒŧäģ˜ä¸Ž (゚テップ 3) だけで済む。
## ゚テップ 3: SPDX ヘッダãƒŧäģ˜ä¸Ž
CLI å‡ē力ãĢは SPDX ヘッダãƒŧがåĢぞれãĒい。**åŋ…ず冒頭ãĢčŋŊ加する** (CI ぎ `spdx` ã‚¸ãƒ§ãƒ–ãŒå¤ąæ•—ã™ã‚‹ãŸã‚)。
```js
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
```
## ゚テップ 4: up / down ぎ整合įĸēčĒ
- `up()` ぎ各゚テãƒŧãƒˆãƒĄãƒŗãƒˆãĢ寞し、`down()` で厌全ãĢåˇģきæˆģせること。
- 列čŋŊ加 (`ADD COLUMN`) ↔ 列削除 (`DROP COLUMN`)、テãƒŧブãƒĢäŊœæˆ ↔ テãƒŧブãƒĢ削除、
FK čŋŊ加 ↔ FK å‰Šé™¤ã€ã‚¤ãƒŗãƒ‡ãƒƒã‚¯ã‚šäŊœæˆ ↔ ã‚¤ãƒŗãƒ‡ãƒƒã‚¯ã‚šå‰Šé™¤ をåŋ…ずペã‚ĸで書く。
- `down()` をįŠēぎぞぞ掋さãĒい。æœŦį•ĒロãƒŧãƒĢバック時ãĢčŠ°ã‚€ã€‚
### ã‚¤ãƒŗãƒ‡ãƒƒã‚¯ã‚ščŋŊåŠ æ™‚ãŽæŗ¨æ„ (CREATE INDEX CONCURRENTLY)
大čĻæ¨Ąãƒ†ãƒŧブãƒĢへぎ `CREATE INDEX` はæœŦį•Ēã§é•ˇæ™‚é–“ãƒ­ãƒƒã‚¯ã™ã‚‹æã‚ŒãŒã‚ã‚‹ã€‚`CONCURRENTLY` でį™ēčĄŒã™ã‚‹ã¨ãã¯ **migration 側ãĢも寞åŋœãŒåŋ…čρ**: PostgreSQL は `CREATE INDEX CONCURRENTLY` を transaction å†…ã§åŽŸčĄŒã§ããĒいため、migration class ãĢäģĨ下をäģ•čžŧんで TypeORM ãĢ「こぎ migration は transaction をåŧĩらãĒい」と指į¤ēする。
å‚į…§åŽŸčŖ…: [packages/backend/migration/1745378064470-composite-note-index.js](../../../packages/backend/migration/1745378064470-composite-note-index.js)。
```js
const isConcurrentIndexMigrationEnabled = process.env.MISSKEY_MIGRATION_CREATE_INDEX_CONCURRENTLY === '1';
export class CompositeNoteIndex1745378064470 {
name = 'CompositeNoteIndex1745378064470';
transaction = isConcurrentIndexMigrationEnabled ? false : undefined;
async up(queryRunner) {
const concurrently = isConcurrentIndexMigrationEnabled;
if (concurrently) {
// CREATE INDEX CONCURRENTLY ...
} else {
// CREATE INDEX ...
}
}
async down(queryRunner) {
// 同様ãĢį’°åĸƒå¤‰æ•°ã§åˆ†å˛
}
}
```
čĻį‚š:
- **`transaction = isConcurrentIndexMigrationEnabled ? false : undefined;`** がåŋ…須。これがãĒいと `CREATE INDEX CONCURRENTLY` が transaction å†…ã§åŽŸčĄŒã•ã‚ŒãĻ `ERROR: CREATE INDEX CONCURRENTLY cannot run inside a transaction block` ã§å¤ąæ•—ã™ã‚‹ã€‚
- į’°åĸƒå¤‰æ•° `MISSKEY_MIGRATION_CREATE_INDEX_CONCURRENTLY=1` がデフりãƒĢト OFF。OFF ぎときは晎通ぎ `CREATE INDEX` (transaction 内) で動くåŋ…čĻãŒã‚ã‚‹ã€‚`up`/`down` åŒæ–šã‚’į’°åĸƒå¤‰æ•°ã§åˆ†å˛ã•せる。
- `ormconfig.js` ぎ `migrationsTransactionMode` は **į’°åĸƒå¤‰æ•°ã§åˆ‡ã‚Šæ›ŋわる**: `MISSKEY_MIGRATION_CREATE_INDEX_CONCURRENTLY=1` ぎときだけ `'each'` (各 migration が個åˆĨ transaction)、æœĒč¨­åŽšæ™‚ã¯ `'all'` (全 migration を 1 つぎ transaction でナップ) ([ormconfig.js:19](../../../packages/backend/ormconfig.js#L19))。晎æŽĩは `'all'` 前提ãĒぎで、CONCURRENTLY をäŊŋう migration ã‚’æ›¸ãæ™‚ã ã‘ã“ãŽãƒ•ãƒŠã‚°ãŽå­˜åœ¨ã‚’æ„č­˜ã™ã‚Œã°č‰¯ã„ã€‚
### é–ĸé€Ŗã‚¨ãƒŗãƒ†ã‚Ŗãƒ†ã‚Ŗã¨ãŽä¸€č‡´
`migration:generate` をäŊŋãŖãŸå ´åˆã€ã‚¨ãƒŗãƒ†ã‚Ŗãƒ†ã‚Ŗå´ãŽ `@Column` / `@Entity` äŋŽæ­Ŗã¨ DB ゚キãƒŧãƒžãŒéŖŸã„é•ã†ã¨ãƒ“ãƒĢド全äŊ“がã‚ēãƒŦã‚‹ã€‚į”ŸæˆåžŒãĢ芲åŊ“ã‚¨ãƒŗãƒ†ã‚Ŗãƒ†ã‚Ŗã¨ SQL ぎ寞åŋœã‚’į›ŽčĻ–įĸēčĒã™ã‚‹ã“ã¨ã€‚
## ゚テップ 5: 検č¨ŧ
ãƒĢãƒŧãƒˆã‹ã‚‰åŽŸčĄŒ:
```bash
# æœĒåæ˜ ãŽåˇŽåˆ†ãŒį„Ąã„ã‹ (新čĻ migration ãŒį”Ÿæˆã™ãšã DDL を取り逃しãĻいãĒいか)
pnpm --filter backend check-migrations
# ロãƒŧã‚ĢãƒĢ DB ãĢéŠį”¨
pnpm migrate
# ロãƒŧãƒĢバック (down ãŒåŖŠã‚ŒãĻいãĒいか)
pnpm revert
# å†éŠį”¨ (順斚向ãĢもう一åēĻ通す)
pnpm migrate
```
`check-migrations` ぎ原äŊ“は [scripts/check_migrations_clean.js](../../../packages/backend/scripts/check_migrations_clean.js)。TypeORM ぎ `dataSource.driver.createSchemaBuilder().log()` で pending DDL を取垗し、`upQueries` / `downQueries` ãŽã„ãšã‚Œã‹ãŒæŽ‹ãŖãĻいれば非ã‚ŧロįĩ‚äē†ã™ã‚‹ã€‚**順åēæ¤œæŸģではãĒく**ã€Œã‚¨ãƒŗãƒ†ã‚Ŗãƒ†ã‚Ŗã¨ migration が同期しãĻいるか」ぎ検æŸģ。
## ゚テップ 6: æ—ĸå­˜ãƒ•ã‚Ąã‚¤ãƒĢå‚į…§ãƒ†ãƒŗãƒ—ãƒŦ
新čĻãƒ•ã‚Ąã‚¤ãƒĢを書くときは、変更パã‚ŋãƒŧãƒŗãŒčŋ‘いæ—ĸå­˜ãƒ•ã‚Ąã‚¤ãƒĢを **åŋ…ãšã˛ã¨ã¤é–‹ã„ãĻä¸ĻずãĻ書く**。゚ã‚ŋイãƒĢがæŋ€ã—くã‚ēãƒŦた PR ã¯åˇŽã—æˆģされやすい。
| パã‚ŋãƒŧãƒŗ | å‚į…§ãƒ•ã‚Ąã‚¤ãƒĢ |
|---|---|
| ã‚¤ãƒŗãƒ‡ãƒƒã‚¯ã‚ščŋŊ加 + é–ĸæ•°åŽšįžŠ | [packages/backend/migration/1767169026317-birthday-index.js](../../../packages/backend/migration/1767169026317-birthday-index.js) |
| 列čŋŊ加ぎãŋ | [packages/backend/migration/1766652173085-add-category-to-avatar-decorations.js](../../../packages/backend/migration/1766652173085-add-category-to-avatar-decorations.js) |
| テãƒŧブãƒĢ新čĻäŊœæˆ + FK | [packages/backend/migration/1761569941833-add-channel-muting.js](../../../packages/backend/migration/1761569941833-add-channel-muting.js) |
クナ゚å‘Ŋ名čĻå‰‡ã¯ **PascalCase 名 + 13 æĄã‚ŋイム゚ã‚ŋãƒŗãƒ—** (例: `class BirthdayIndex1767169026317`)。`name` ãƒ—ãƒ­ãƒ‘ãƒ†ã‚Ŗã‚‚ã‚¯ãƒŠã‚šåã¨åŒä¸€æ–‡å­—åˆ—ãĢする。
## ゚テップ 7: CHANGELOG (ãƒĻãƒŧã‚ļãƒŧåŊąéŸŋがある場合)
゚キãƒŧマ変更がãƒĻãƒŧã‚ļãƒŧãĢčĻ‹ãˆã‚‹æŒ™å‹•ã‚’į”Ÿã‚€å ´åˆãŽãŋ、`CHANGELOG.md` ぎ `## Unreleased` → `### Server` ぞたは `### General` ãĢ 1 行čŋŊ加する ([AGENTS.md §CHANGELOG](../../../AGENTS.md#changelog) å‚į…§)。内部ãƒĒãƒ•ã‚Ąã‚¯ã‚ŋã‚„į´”į˛‹ãĒã‚¤ãƒŗãƒ‡ãƒƒã‚¯ã‚ščŋŊ加は不čĻã€‚

View File

@@ -165,11 +165,6 @@ id: 'aidx'
# dsn: 'https://examplePublicKey@o0.ingest.sentry.io/0'
#sentryForFrontend:
# vueIntegration:
# tracingOptions:
# trackComponents: true
# browserTracingIntegration:
# replayIntegration:
# options:
# dsn: 'https://examplePublicKey@o0.ingest.sentry.io/0'
@@ -182,9 +177,6 @@ id: 'aidx'
# Number of worker processes
#clusterLimit: 1
# Number of threads of extra thread pool for CPU-intensive tasks (per worker)
#threadPoolSize: 1
# Job concurrency per worker
# deliverJobConcurrency: 128
# inboxJobConcurrency: 16
@@ -218,9 +210,20 @@ proxyBypassHosts:
# Media Proxy
#mediaProxy: https://example.com/proxy
# Proxy remote files (default: true)
proxyRemoteFiles: true
# Sign to ActivityPub GET request (default: true)
signToActivityPubGet: true
allowedPrivateNetworks: [
'127.0.0.1/32'
]
# Disable automatic redirect for ActivityPub object lookup. (default: false)
# This is a strong defense against potential impersonation attacks if the viewer instance has inadequate validation.
# However it will make it impossible for other instances to lookup third-party user and notes through your URL.
#disallowExternalApRedirect: true
# Upload or download file size limits (bytes)
#maxFileSize: 262144000

View File

@@ -177,11 +177,6 @@ id: 'aidx'
# dsn: 'https://examplePublicKey@o0.ingest.sentry.io/0'
#sentryForFrontend:
# vueIntegration:
# tracingOptions:
# trackComponents: true
# browserTracingIntegration:
# replayIntegration:
# options:
# dsn: 'https://examplePublicKey@o0.ingest.sentry.io/0'
@@ -194,9 +189,6 @@ id: 'aidx'
# Number of worker processes
#clusterLimit: 1
# Number of threads of extra thread pool for CPU-intensive tasks (per worker)
#threadPoolSize: 1
# Job concurrency per worker
# deliverJobConcurrency: 128
# inboxJobConcurrency: 16
@@ -230,6 +222,12 @@ proxyBypassHosts:
# Media Proxy
#mediaProxy: https://example.com/proxy
# Proxy remote files (default: true)
proxyRemoteFiles: true
# Sign to ActivityPub GET request (default: true)
signToActivityPubGet: true
# For security reasons, uploading attachments from the intranet is prohibited,
# but exceptions can be made from the following settings. Default value is "undefined".
# Read changelog to learn more (Improvements of 12.90.0 (2021/09/04)).
@@ -237,6 +235,11 @@ proxyBypassHosts:
# '127.0.0.1/32'
#]
# Disable automatic redirect for ActivityPub object lookup. (default: false)
# This is a strong defense against potential impersonation attacks if the viewer instance has inadequate validation.
# However it will make it impossible for other instances to lookup third-party user and notes through your URL.
#disallowExternalApRedirect: true
# Upload or download file size limits (bytes)
#maxFileSize: 262144000

View File

@@ -105,54 +105,6 @@ port: 3000
# socket: /path/to/misskey.sock
# chmodSocket: '777'
# Proxy trust settings
#
# Specifies the IP addresses that Misskey will use as trusted
# reverse proxies (e.g., nginx, Cloudflare). This affects how
# Misskey determines the source IP for each request and is used
# for important rate limiting and security features. If the value
# is not set correctly, Misskey may use the IP address of the
# reverse proxy instead of the actual source IP, which may lead to
# unintended rate limiting or security vulnerabilities.
# By default, the loopback network and private network address
# ranges shown below are trusted.
# If you are using a single reverse proxy and it is on the same
# machine or the same private network as Misskey, it is unlikely you
# need to change this setting, and the default setting is fine.
# Also, if you are using multiple reverse proxy servers and they are
# all on the same private network as Misskey, the default setting
# is fine.
# However, if you are using a reverse proxy server that accesses
# Misskey web servers and streaming servers via public IP addresses
# (for example, Cloudflare), you must set this variable.
# When changing this setting, you can use one of the following values:
#
# - true: Trust all proxies
# - false: Do not trust any proxies
# - IP address, IP address range, or array of them: Trust hops that
# match the specified criteria.
# - Integer: Trust the nth hop from the front-facing proxy server as
# the client.
# For more information on how to configure this setting, please refer
# to the Fastify documentation:
# https://fastify.dev/docs/latest/Reference/Server/#trustproxy
#
# Note that if this variable is set, it overrides the default range,
# so if you have both an external reverse proxy and a proxy on the
# local host, you must include both IPs (or IP ranges).
#
#trustProxy:
# - '10.0.0.0/8'
# - '172.16.0.0/12'
# - '192.168.0.0/16'
# - '127.0.0.1/32'
# - '::1/128'
# - 'fc00::/7'
# # Example: If you are using some external reverse proxies like CDNs,
# # you may need to add the CDN IP ranges here.
# # If you're using Cloudflare, you can find IP Ranges at:
# # https://www.cloudflare.com/ips/
# ┌──────────────────────────┐
#───┘ PostgreSQL configuration └────────────────────────────────
@@ -307,11 +259,6 @@ id: 'aidx'
# dsn: 'https://examplePublicKey@o0.ingest.sentry.io/0'
#sentryForFrontend:
# vueIntegration:
# tracingOptions:
# trackComponents: true
# browserTracingIntegration:
# replayIntegration:
# options:
# dsn: 'https://examplePublicKey@o0.ingest.sentry.io/0'
@@ -321,16 +268,9 @@ id: 'aidx'
# Whether disable HSTS
#disableHsts: true
# Enable internal IP-based rate limiting (default: true)
# To configure them in reverse proxy instead, set this to false.
#enableIpRateLimit: true
# Number of worker processes
#clusterLimit: 1
# Number of threads of extra thread pool for CPU-intensive tasks (per worker)
#threadPoolSize: 1
# Job concurrency per worker
#deliverJobConcurrency: 128
#inboxJobConcurrency: 16
@@ -374,12 +314,19 @@ proxyBypassHosts:
# * Perform image compression (on a different server resource than the main process)
#mediaProxy: https://example.com/proxy
# Proxy remote files (default: true)
# Proxy remote files by this instance or mediaProxy to prevent remote files from running in remote domains.
proxyRemoteFiles: true
# Movie Thumbnail Generation URL
# There is no reference implementation.
# For example, Misskey will point to the following URL:
# https://example.com/thumbnail.webp?thumbnail=1&url=https%3A%2F%2Fstorage.example.com%2Fpath%2Fto%2Fvideo.mp4
#videoThumbnailGenerator: https://example.com
# Sign to ActivityPub GET request (default: true)
signToActivityPubGet: true
# For security reasons, uploading attachments from the intranet is prohibited,
# but exceptions can be made from the following settings. Default value is "undefined".
# Read changelog to learn more (Improvements of 12.90.0 (2021/09/04)).
@@ -387,6 +334,11 @@ proxyBypassHosts:
# '127.0.0.1/32'
#]
# Disable automatic redirect for ActivityPub object lookup. (default: false)
# This is a strong defense against potential impersonation attacks if the viewer instance has inadequate validation.
# However it will make it impossible for other instances to lookup third-party user and notes through your URL.
#disallowExternalApRedirect: true
# Upload or download file size limits (bytes)
#maxFileSize: 262144000

View File

@@ -1 +1 @@
FROM mcr.microsoft.com/devcontainers/javascript-node:4.0.3-24-trixie
FROM mcr.microsoft.com/devcontainers/javascript-node:0-18

View File

@@ -28,7 +28,7 @@ services:
db:
restart: unless-stopped
image: postgres:18-alpine
image: postgres:15-alpine
networks:
- internal_network
environment:
@@ -36,7 +36,7 @@ services:
POSTGRES_PASSWORD: postgres
POSTGRES_DB: misskey
volumes:
- postgres-data:/var/lib/postgresql
- postgres-data:/var/lib/postgresql/data
healthcheck:
test: "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"
interval: 5s

View File

@@ -5,10 +5,10 @@
"workspaceFolder": "/workspace",
"features": {
"ghcr.io/devcontainers/features/node:1": {
"version": "22.15.0"
"version": "22.11.0"
},
"ghcr.io/devcontainers-extra/features/pnpm:2": {
"version": "10.10.0"
"version": "10.6.1"
}
},
"forwardPorts": [3000],
@@ -19,6 +19,7 @@
"editorconfig.editorconfig",
"dbaeumer.vscode-eslint",
"Vue.volar",
"Orta.vscode-jest",
"dbaeumer.vscode-eslint",
"mrmlnc.vscode-json5"
]

View File

@@ -152,11 +152,6 @@ id: 'aidx'
# dsn: 'https://examplePublicKey@o0.ingest.sentry.io/0'
#sentryForFrontend:
# vueIntegration:
# tracingOptions:
# trackComponents: true
# browserTracingIntegration:
# replayIntegration:
# options:
# dsn: 'https://examplePublicKey@o0.ingest.sentry.io/0'
@@ -169,9 +164,6 @@ id: 'aidx'
# Number of worker processes
#clusterLimit: 1
# Number of threads of extra thread pool for CPU-intensive tasks (per worker)
#threadPoolSize: 1
# Job concurrency per worker
# deliverJobConcurrency: 128
# inboxJobConcurrency: 16
@@ -205,6 +197,12 @@ proxyBypassHosts:
# Media Proxy
#mediaProxy: https://example.com/proxy
# Proxy remote files (default: true)
proxyRemoteFiles: true
# Sign to ActivityPub GET request (default: true)
signToActivityPubGet: true
allowedPrivateNetworks: [
'127.0.0.1/32'
]

View File

@@ -6,7 +6,6 @@
Dockerfile
build/
built/
src-js/
db/
.devcontainer/compose.yml
node_modules/

View File

@@ -13,7 +13,3 @@ trim_trailing_whitespace = false
[*.{yml,yaml}]
indent_style = space
[packages/backend/migration/*.js]
indent_style = space
indent_size = 4

View File

@@ -54,7 +54,7 @@ body:
* Model and OS of the device(s): MacBook Pro (14inch, 2021), macOS Ventura 13.4
* Browser: Chrome 113.0.5672.126
* Server URL: misskey.example.com
* Misskey: 2026.x.x
* Misskey: 2025.x.x
value: |
* Model and OS of the device(s):
* Browser:
@@ -74,9 +74,9 @@ body:
Examples:
* Installation Method or Hosting Service: docker compose, k8s/docker, systemd, "Misskey install shell script", development environment
* Misskey: 2026.x.x
* Misskey: 2025.x.x
* Node: 20.x.x
* PostgreSQL: 18.x.x
* PostgreSQL: 15.x.x
* Redis: 7.x.x
* OS and Architecture: Ubuntu 24.04.2 LTS aarch64
value: |

View File

@@ -1,54 +0,0 @@
# Copilot Instructions for Misskey
ã“ãŽãƒ•ã‚Ąã‚¤ãƒĢは GitHub Copilot ぎ repository-wide instructions としãĻäŊŋわれる。Copilot code review では `AGENTS.md` がčĒ­ãžã‚ŒãĒã„į’°åĸƒãŒã‚るため、ãƒŦビãƒĨãƒŧやčģŊ垎ãĒåŽŸčŖ…åˆ¤æ–­ãĢåŋ…čρãĒčĻį´„ã¯ã“ãŽãƒ•ã‚Ąã‚¤ãƒĢ単äŊ“でæē€ãŸã™ã“と。
こぎãƒĒポジトãƒĒは Misskey ぎ pnpm workspace ãƒĸノãƒŦポ。ä¸ģčρãĒåŽŸčŖ…ã¯ `packages/backend` (NestJS / TypeORM) と `packages/frontend` (Vue 3) ãĢã‚ã‚‹ã€‚ã‚ˆã‚ŠčŠŗã—ã„ã‚ŦイドはãƒĒポジトãƒĒãƒĢãƒŧトぎ `AGENTS.md` ã‚’å‚į…§ã—ãĻã‚ˆã„ãŒã€ã“ãŽãƒ•ã‚Ąã‚¤ãƒĢぎčρäģļã‚’įœį•ĨしãĻããĄã‚‰ã¸ãŽå‚į…§ã ã‘ã§æ¸ˆãžã›ãĒいこと。
## Always follow
- AGPL-3.0-only įŽĄčŊ„かつ SPDX CI å¯žčąĄãƒ‡ã‚ŖãƒŦクトãƒĒãĢ新čĻ `.ts` / `.js` / `.cjs` / `.mjs` / `.scss` ãƒ•ã‚Ąã‚¤ãƒĢをčŋŊ加する場合は、åŋ…ずæŦĄãŽ SPDX ヘッダãƒŧをäģ˜ã‘ã‚‹ã€‚čŠŗį´°ãĒå¯žčąĄåˆ¤åŽšã¯ `AGENTS.md` と `.github/workflows/check-spdx-license-id.yml` ã‚’å‚į…§ã™ã‚‹ã“ã¨ã€‚
```text
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
```
- AGPL-3.0-only įŽĄčŊ„かつ SPDX CI å¯žčąĄãƒ‡ã‚ŖãƒŦクトãƒĒãĢ新čĻ `.vue` / `.html` ãƒ•ã‚Ąã‚¤ãƒĢをčŋŊ加する場合は、åŋ…ずæŦĄãŽ SPDX ヘッダãƒŧをäģ˜ã‘る。
```text
<!--
SPDX-FileCopyrightText: syuilo and misskey-project
SPDX-License-Identifier: AGPL-3.0-only
-->
```
`packages/misskey-js` は MIT ナイã‚ģãƒŗã‚šãŽã‚ĩãƒ–ãƒ‘ãƒƒã‚ąãƒŧジãĒぎで、こぎ AGPL ヘッダãƒŧを一型ãĢäģ˜ã‘ãĒい。ã‚ĩãƒ–ãƒ‘ãƒƒã‚ąãƒŧジå›ē有ぎ `package.json` / `LICENSE` / æ—ĸå­˜ãƒ•ã‚Ąã‚¤ãƒĢぎヘッダãƒŧãĢ垓う。
- `locales/` 配下ぎ YAML は `ja-JP.yml` ぎãŋæ‰‹å‹•įˇ¨é›†ã—ãĻよい。äģ–言čĒžã¯ Crowdin ぎč‡Ē動配äŋĄå…ˆãĒãŽã§æ‰‹å‹•įˇ¨é›†ã—ãĒいこと。
- `packages/backend/migration/{timestamp}-*.js` ãŽã†ãĄã€æ—ĸãĢマãƒŧジ済ãŋぎ migration はįĩļ寞ãĢįˇ¨é›†ã—ãĒい。゚キãƒŧマ変更がåŋ…čρãĒ場合は新しい timestamp で migration をčŋŊ加し、`up()` と `down()` ãŽä¸Ąæ–šã‚’åŽŸčŖ…ã™ã‚‹ã“ã¨ã€‚
- ãƒĻãƒŧã‚ļãƒŧåŊąéŸŋぎある変更は `CHANGELOG.md` ぎ `## Unreleased` 配下ぎ `### General` / `### Client` / `### Server` ぎいずれかãĢ 1 行čŋŊ加する。内部ãƒĒãƒ•ã‚Ąã‚¯ã‚ŋぎãŋãĒら不čĻã€‚
- API 変更時は `pnpm build-misskey-js-with-types` ãŽåŽŸčĄŒãŒåŋ…čρãĢãĒる。
## Validation
- 全äŊ“ビãƒĢド: `pnpm build`
- 全äŊ“ lint / typecheck: `pnpm lint`
- Backend unit test: `pnpm --filter backend test`
- Backend e2e test: `pnpm --filter backend test:e2e`
- Backend federation test: `pnpm --filter backend test:fed`
- Frontend test: `pnpm --filter frontend test`
- Migration åˇŽåˆ†æ¤œæŸģ: `pnpm --filter backend check-migrations`
> **backend テ゚ト (`test` / `test:e2e` / `test:fed`) åŽŸčĄŒå‰ãĢ `.config/test.yml` がåŋ…čĻã€‚** æœĒäŊœæˆãŽå ´åˆã¯ `ncp .github/misskey/test.yml .config/test.yml` (ぞたは `cp .github/misskey/test.yml .config/test.yml`) ã‚’åŽŸčĄŒã—ãĻからčĩ°ã‚‰ã›ã‚‹ã€‚各テ゚ト゚クãƒĒプトが内部で `cross-env NODE_ENV=test pnpm compile-config` をå‘ŧãļãŸã‚ã€ã‚ŗãƒ”ãƒŧ済ãŋであればčŋŊ加ぎ compile-config は不čĻã€‚
å¤‰æ›´į¯„å›˛ãĢåŋœã˜ãĻ最もčŋ‘ã„ã‚ŗãƒžãƒŗãƒ‰ã‹ã‚‰å„Ē先しãĻ検č¨ŧし、åŋ…čρãĒら全äŊ“ã‚ŗãƒžãƒŗãƒ‰ãĢåēƒã’ること。
## Editing hints
- Backend ぎ API / migration / TypeORM 変更は `packages/backend` をčĻ‹ã‚‹ã€‚
- Frontend ぎ Vue ã‚ŗãƒŗãƒãƒŧãƒãƒŗãƒˆã‚„ãƒšãƒŧジ変更は `packages/frontend` をčĻ‹ã‚‹ã€‚
- `AGENTS.md` å†…ãŽį›¸å¯žãƒĒãƒŗã‚¯ã¯ãƒĒポジトãƒĒãƒĢãƒŧトčĩˇį‚šã§č§Ŗæąēã™ã‚‹æƒŗåŽšã€‚
> `AGENTS.md` ã¯ã‚ˆã‚ŠčŠŗį´°ãĒæ­Ŗå…¸ã ãŒã€Copilot code review ã§ã¯ã“ãŽãƒ•ã‚Ąã‚¤ãƒĢがä¸ģãĒå…ĨåŖãĢãĒã‚‹ã€‚ä¸Ąæ–šãŒčĒ­ãžã‚Œã‚‹į’°åĸƒã§ã¯ `AGENTS.md` ã‚’čŖœåŠŠæƒ…å ąã¨ã—ãĻäŊŋãŖãĻよい。

View File

@@ -24,6 +24,9 @@ updates:
aws-sdk:
patterns:
- "@aws-sdk/*"
bull-board:
patterns:
- "@bull-board/*"
nestjs:
patterns:
- "@nestjs/*"
@@ -34,6 +37,9 @@ updates:
patterns:
- "storybook*"
- "@storybook/*"
swc-core:
patterns:
- "@swc/core*"
typescript-eslint:
patterns:
- "@typescript-eslint/*"

View File

@@ -1 +0,0 @@
22.15.0

View File

@@ -15,5 +15,3 @@ redis:
host: 127.0.0.1
port: 56312
id: aidx
proxyRemoteFiles: true

View File

@@ -16,13 +16,13 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v6.0.2
uses: actions/checkout@v4.2.2
- name: Setup pnpm
uses: pnpm/action-setup@v6.0.3
uses: pnpm/action-setup@v4.1.0
- name: Setup Node.js
uses: actions/setup-node@v6.4.0
uses: actions/setup-node@v4.2.0
with:
node-version-file: '.node-version'
cache: 'pnpm'

View File

@@ -12,9 +12,9 @@ jobs:
steps:
- name: Checkout head
uses: actions/checkout@v6.0.2
uses: actions/checkout@v4.2.2
- name: Setup Node.js
uses: actions/setup-node@v6.4.0
uses: actions/setup-node@v4.2.0
with:
node-version-file: '.node-version'

View File

@@ -18,18 +18,18 @@ jobs:
if: ${{ github.event.pull_request.mergeable == null || github.event.pull_request.mergeable == true }}
steps:
- name: checkout
uses: actions/checkout@v6.0.2
uses: actions/checkout@v4.2.2
with:
submodules: true
persist-credentials: false
ref: refs/pull/${{ github.event.pull_request.number }}/merge
- name: setup pnpm
uses: pnpm/action-setup@v6
uses: pnpm/action-setup@v4
- name: setup node
id: setup-node
uses: actions/setup-node@v6.4.0
uses: actions/setup-node@v4.2.0
with:
node-version-file: '.node-version'
cache: pnpm
@@ -53,7 +53,7 @@ jobs:
# packages/misskey-js/generator/built/autogen
- name: Upload Generated
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@v4
with:
name: generated-misskey-js
path: packages/misskey-js/generator/built/autogen
@@ -66,14 +66,14 @@ jobs:
if: ${{ github.event.pull_request.mergeable == null || github.event.pull_request.mergeable == true }}
steps:
- name: checkout
uses: actions/checkout@v6.0.2
uses: actions/checkout@v4.2.2
with:
submodules: true
persist-credentials: false
ref: refs/pull/${{ github.event.pull_request.number }}/merge
- name: Upload From Merged
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@v4
with:
name: actual-misskey-js
path: packages/misskey-js/src/autogen
@@ -86,13 +86,13 @@ jobs:
pull-requests: write
steps:
- name: download generated-misskey-js
uses: actions/download-artifact@v8
uses: actions/download-artifact@v4
with:
name: generated-misskey-js
path: misskey-js-generated
- name: download actual-misskey-js
uses: actions/download-artifact@v8
uses: actions/download-artifact@v4
with:
name: actual-misskey-js
path: misskey-js-actual
@@ -113,9 +113,9 @@ jobs:
- name: send message
if: steps.check-changes.outputs.changes == 'true'
uses: thollander/actions-comment-pull-request@v3
uses: thollander/actions-comment-pull-request@v2
with:
comment-tag: check-misskey-js-autogen
comment_tag: check-misskey-js-autogen
message: |-
Thank you for sending us a great Pull Request! 👍
Please regenerate misskey-js type definitions! 🙏
@@ -127,9 +127,9 @@ jobs:
- name: send message
if: steps.check-changes.outputs.changes == 'false'
uses: thollander/actions-comment-pull-request@v3
uses: thollander/actions-comment-pull-request@v2
with:
comment-tag: check-misskey-js-autogen
comment_tag: check-misskey-js-autogen
mode: delete
message: "Thank you!"
create_if_not_exists: false

View File

@@ -20,7 +20,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6.0.2
uses: actions/checkout@v4.2.2
- name: Check version
run: |
if [ "$(jq -r '.version' package.json)" != "$(jq -r '.version' packages/misskey-js/package.json)" ]; then

View File

@@ -12,7 +12,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6.0.2
uses: actions/checkout@v4.2.2
- name: Check
run: |
counter=0
@@ -50,7 +50,6 @@ jobs:
"packages/backend/test"
"packages/frontend-shared/@types"
"packages/frontend-shared/js"
"packages/frontend-builder"
"packages/frontend/.storybook"
"packages/frontend/@types"
"packages/frontend/lib"
@@ -59,7 +58,6 @@ jobs:
"packages/frontend/test"
"packages/frontend-embed/@types"
"packages/frontend-embed/src"
"packages/icons-subsetter/src"
"packages/misskey-bubble-game/src"
"packages/misskey-reversi/src"
"packages/sw/src"

View File

@@ -10,7 +10,7 @@ jobs:
check_copyright_year:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6.0.2
- uses: actions/checkout@v4.2.2
- run: |
if [ "$(grep Copyright COPYING | sed -e 's/.*2014-\([0-9]*\) .*/\1/g')" -ne "$(date +%Y)" ]; then
echo "Please change copyright year!"

View File

@@ -28,7 +28,7 @@ jobs:
wait_time: ${{ steps.get-wait-time.outputs.wait_time }}
steps:
- name: Checkout
uses: actions/checkout@v6.0.2
uses: actions/checkout@v4.2.2
- name: Check allowed users
id: check-allowed-users

View File

@@ -27,17 +27,17 @@ jobs:
platform=${{ matrix.platform }}
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
- name: Check out the repo
uses: actions/checkout@v6.0.2
uses: actions/checkout@v4.2.2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
uses: docker/setup-buildx-action@v3
- name: Log in to Docker Hub
uses: docker/login-action@v4
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build and push by digest
id: build
uses: docker/build-push-action@v7
uses: docker/build-push-action@v6
with:
context: .
push: true
@@ -53,7 +53,7 @@ jobs:
digest="${{ steps.build.outputs.digest }}"
touch "/tmp/digests/${digest#sha256:}"
- name: Upload digest
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@v4
with:
name: digests-${{ env.PLATFORM_PAIR }}
path: /tmp/digests/*
@@ -66,15 +66,15 @@ jobs:
- build
steps:
- name: Download digests
uses: actions/download-artifact@v8
uses: actions/download-artifact@v4
with:
path: /tmp/digests
pattern: digests-*
merge-multiple: true
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
uses: docker/setup-buildx-action@v3
- name: Login to Docker Hub
uses: docker/login-action@v4
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}

View File

@@ -32,23 +32,23 @@ jobs:
platform=${{ matrix.platform }}
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
- name: Check out the repo
uses: actions/checkout@v6.0.2
uses: actions/checkout@v4.2.2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
uses: docker/setup-buildx-action@v3
- name: Docker meta
id: meta
uses: docker/metadata-action@v6
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY_IMAGE }}
tags: ${{ env.TAGS }}
- name: Log in to Docker Hub
uses: docker/login-action@v4
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build and Push to Docker Hub
id: build
uses: docker/build-push-action@v7
uses: docker/build-push-action@v6
with:
context: .
push: true
@@ -64,7 +64,7 @@ jobs:
digest="${{ steps.build.outputs.digest }}"
touch "/tmp/digests/${digest#sha256:}"
- name: Upload digest
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@v4
with:
name: digests-${{ env.PLATFORM_PAIR }}
path: /tmp/digests/*
@@ -77,21 +77,21 @@ jobs:
- build
steps:
- name: Download digests
uses: actions/download-artifact@v8
uses: actions/download-artifact@v4
with:
path: /tmp/digests
pattern: digests-*
merge-multiple: true
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
uses: docker/setup-buildx-action@v3
- name: Docker meta
id: meta
uses: docker/metadata-action@v6
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY_IMAGE }}
tags: ${{ env.TAGS }}
- name: Login to Docker Hub
uses: docker/login-action@v4
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}

View File

@@ -11,43 +11,22 @@ on:
jobs:
dockle:
runs-on: ubuntu-latest
env:
DOCKER_CONTENT_TRUST: 1
DOCKLE_VERSION: 0.4.15
DOCKLE_VERSION: 0.4.14
steps:
- uses: actions/checkout@v6.0.2
- uses: actions/checkout@v4.2.2
- name: Download and install dockle v${{ env.DOCKLE_VERSION }}
run: |
set -eux
curl -L -o dockle.deb "https://github.com/goodwithtech/dockle/releases/download/v${DOCKLE_VERSION}/dockle_${DOCKLE_VERSION}_Linux-64bit.deb"
sudo dpkg -i dockle.deb
- name: Build web image (docker build)
run: |
set -eux
docker build -t "misskey-web:ci" .
docker image ls
- name: Mount tmpfs for Dockle tar
env:
TMPFS_SIZE: 8G
run: |
set -eux
sudo mkdir -p /mnt/dockle-tmp
sudo mount -t tmpfs -o size=${{ env.TMPFS_SIZE }} tmpfs /mnt/dockle-tmp
free -h
df -h
- name: Save image tar into tmpfs
run: |
set -eux
docker save misskey-web:ci -o /mnt/dockle-tmp/misskey-web.tar
ls -lh /mnt/dockle-tmp/misskey-web.tar
- name: Run Dockle Scan (tar input)
run: |
set -eux
dockle --exit-code 1 --input /mnt/dockle-tmp/misskey-web.tar
- run: |
cp .config/docker_example.env .config/docker.env
cp ./compose_example.yml ./compose.yml
- run: |
docker compose up -d web
docker tag "$(docker compose images web | awk 'OFS=":" {print $4}' | tail -n +2)" misskey-web:latest
- run: |
cmd="dockle --exit-code 1 misskey-web:latest ${image_name}"
echo "> ${cmd}"
eval "${cmd}"

View File

@@ -17,6 +17,7 @@ jobs:
strategy:
matrix:
node-version: [22.11.0]
api-json-name: [api-base.json, api-head.json]
include:
- api-json-name: api-base.json
@@ -25,16 +26,16 @@ jobs:
ref: refs/pull/${{ github.event.number }}/merge
steps:
- uses: actions/checkout@v6.0.2
- uses: actions/checkout@v4.2.2
with:
ref: ${{ matrix.ref }}
submodules: true
- name: Setup pnpm
uses: pnpm/action-setup@v6.0.3
- name: Use Node.js
uses: actions/setup-node@v6.4.0
uses: pnpm/action-setup@v4.1.0
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4.2.0
with:
node-version-file: '.node-version'
node-version: ${{ matrix.node-version }}
cache: 'pnpm'
- run: pnpm i --frozen-lockfile
- name: Check pnpm-lock.yaml
@@ -48,7 +49,7 @@ jobs:
- name: Copy API.json
run: cp packages/backend/built/api.json ${{ matrix.api-json-name }}
- name: Upload Artifact
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@v4
with:
name: api-artifact-${{ matrix.api-json-name }}
path: ${{ matrix.api-json-name }}
@@ -61,7 +62,7 @@ jobs:
PR_NUMBER: ${{ github.event.number }}
run: |
echo "$PR_NUMBER" > ./pr_number
- uses: actions/upload-artifact@v7
- uses: actions/upload-artifact@v4
with:
name: api-artifact-pr-number
path: pr_number

View File

@@ -1,87 +0,0 @@
# this name is used in report-backend-memory.yml so be careful when change name
name: Get backend memory usage
on:
pull_request:
branches:
- master
- develop
paths:
- packages/backend/**
- packages/misskey-js/**
- .github/workflows/get-backend-memory.yml
jobs:
get-memory-usage:
runs-on: ubuntu-latest
permissions:
contents: read
strategy:
matrix:
memory-json-name: [memory-base.json, memory-head.json]
include:
- memory-json-name: memory-base.json
ref: ${{ github.base_ref }}
- memory-json-name: memory-head.json
ref: refs/pull/${{ github.event.number }}/merge
services:
postgres:
image: postgres:18
ports:
- 54312:5432
env:
POSTGRES_DB: test-misskey
POSTGRES_HOST_AUTH_METHOD: trust
redis:
image: redis:8
ports:
- 56312:6379
steps:
- uses: actions/checkout@v6.0.2
with:
ref: ${{ matrix.ref }}
submodules: true
- name: Setup pnpm
uses: pnpm/action-setup@v6.0.3
- name: Use Node.js
uses: actions/setup-node@v6.4.0
with:
node-version-file: '.node-version'
cache: 'pnpm'
- run: pnpm i --frozen-lockfile
- name: Check pnpm-lock.yaml
run: git diff --exit-code pnpm-lock.yaml
- name: Copy Configure
run: cp .github/misskey/test.yml .config/default.yml
- name: Compile Configure
run: pnpm compile-config
- name: Build
run: pnpm build
- name: Run migrations
run: pnpm --filter backend migrate
- name: Measure memory usage
run: |
# Start the server and measure memory usage
node packages/backend/scripts/measure-memory.mjs > ${{ matrix.memory-json-name }}
- name: Upload Artifact
uses: actions/upload-artifact@v7
with:
name: memory-artifact-${{ matrix.memory-json-name }}
path: ${{ matrix.memory-json-name }}
save-pr-number:
runs-on: ubuntu-latest
permissions: {}
steps:
- name: Save PR number
env:
PR_NUMBER: ${{ github.event.number }}
run: |
echo "$PR_NUMBER" > ./pr_number
- uses: actions/upload-artifact@v7
with:
name: memory-artifact-pr-number
path: pr_number

View File

@@ -11,6 +11,6 @@ jobs:
pull-requests: write
runs-on: ubuntu-latest
steps:
- uses: actions/labeler@v6
- uses: actions/labeler@v5
with:
repo-token: "${{ secrets.GITHUB_TOKEN }}"

View File

@@ -9,9 +9,7 @@ on:
- packages/backend/**
- packages/frontend/**
- packages/frontend-shared/**
- packages/frontend-builder/**
- packages/frontend-embed/**
- packages/icons-subsetter/**
- packages/sw/**
- packages/misskey-js/**
- packages/misskey-bubble-game/**
@@ -23,9 +21,7 @@ on:
- packages/backend/**
- packages/frontend/**
- packages/frontend-shared/**
- packages/frontend-builder/**
- packages/frontend-embed/**
- packages/icons-subsetter/**
- packages/sw/**
- packages/misskey-js/**
- packages/misskey-bubble-game/**
@@ -36,13 +32,13 @@ jobs:
pnpm_install:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6.0.2
- uses: actions/checkout@v4.2.2
with:
fetch-depth: 0
submodules: true
- name: Setup pnpm
uses: pnpm/action-setup@v6.0.3
- uses: actions/setup-node@v6.4.0
uses: pnpm/action-setup@v4.1.0
- uses: actions/setup-node@v4.2.0
with:
node-version-file: '.node-version'
cache: 'pnpm'
@@ -58,9 +54,7 @@ jobs:
- backend
- frontend
- frontend-shared
- frontend-builder
- frontend-embed
- icons-subsetter
- sw
- misskey-js
- misskey-bubble-game
@@ -69,19 +63,19 @@ jobs:
eslint-cache-version: v1
eslint-cache-path: ${{ github.workspace }}/node_modules/.cache/eslint-${{ matrix.workspace }}
steps:
- uses: actions/checkout@v6.0.2
- uses: actions/checkout@v4.2.2
with:
fetch-depth: 0
submodules: true
- name: Setup pnpm
uses: pnpm/action-setup@v6.0.3
- uses: actions/setup-node@v6.4.0
uses: pnpm/action-setup@v4.1.0
- uses: actions/setup-node@v4.2.0
with:
node-version-file: '.node-version'
cache: 'pnpm'
- run: pnpm i --frozen-lockfile
- name: Restore eslint cache
uses: actions/cache@v5.0.5
uses: actions/cache@v4.2.2
with:
path: ${{ env.eslint-cache-path }}
key: eslint-${{ env.eslint-cache-version }}-${{ matrix.workspace }}-${{ hashFiles('**/pnpm-lock.yaml') }}-${{ github.ref_name }}-${{ github.sha }}
@@ -96,20 +90,22 @@ jobs:
matrix:
workspace:
- backend
- frontend
- sw
- misskey-js
steps:
- uses: actions/checkout@v6.0.2
- uses: actions/checkout@v4.2.2
with:
fetch-depth: 0
submodules: true
- name: Setup pnpm
uses: pnpm/action-setup@v6.0.3
- uses: actions/setup-node@v6.4.0
uses: pnpm/action-setup@v4.1.0
- uses: actions/setup-node@v4.2.0
with:
node-version-file: '.node-version'
cache: 'pnpm'
- run: pnpm i --frozen-lockfile
- run: pnpm --filter "${{ matrix.workspace }}^..." run build
- run: pnpm --filter misskey-js run build
if: ${{ matrix.workspace == 'backend' || matrix.workspace == 'sw' }}
- run: pnpm --filter misskey-reversi run build
if: ${{ matrix.workspace == 'backend' }}
- run: pnpm --filter ${{ matrix.workspace }} run typecheck

View File

@@ -3,12 +3,10 @@ name: Lint
on:
push:
paths:
- packages/i18n/**
- locales/**
- .github/workflows/locale.yml
pull_request:
paths:
- packages/i18n/**
- locales/**
- .github/workflows/locale.yml
jobs:
@@ -16,18 +14,15 @@ jobs:
runs-on: ubuntu-latest
continue-on-error: true
steps:
- uses: actions/checkout@v6.0.2
with:
fetch-depth: 0
submodules: true
- name: Setup pnpm
uses: pnpm/action-setup@v6.0.3
- uses: actions/setup-node@v6.4.0
with:
node-version-file: ".node-version"
cache: "pnpm"
- run: pnpm i --frozen-lockfile
- run: pnpm --filter i18n build
- name: Verify Locales
working-directory: ./packages/i18n
run: pnpm run verify
- uses: actions/checkout@v4.2.2
with:
fetch-depth: 0
submodules: true
- name: Setup pnpm
uses: pnpm/action-setup@v4.1.0
- uses: actions/setup-node@v4.2.0
with:
node-version-file: '.node-version'
cache: 'pnpm'
- run: pnpm i --frozen-lockfile
- run: cd locales && node verify.js

View File

@@ -15,22 +15,22 @@ jobs:
contents: read
id-token: write
strategy:
matrix:
node-version: [22.11.0]
steps:
- uses: actions/checkout@v6.0.2
- uses: actions/checkout@v4.2.2
with:
submodules: true
- name: Setup pnpm
uses: pnpm/action-setup@v6.0.3
- name: Use Node.js
uses: actions/setup-node@v6.4.0
uses: pnpm/action-setup@v4.1.0
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4.2.0
with:
node-version-file: '.node-version'
node-version: ${{ matrix.node-version }}
cache: 'pnpm'
# see https://docs.github.com/actions/use-cases-and-examples/publishing-packages/publishing-nodejs-packages#publishing-packages-to-the-npm-registry
registry-url: 'https://registry.npmjs.org'
# Ensure npm 11.5.1 or later is installed
- name: Update npm
run: npm install -g npm@latest
- name: Publish package
run: |
pnpm i --frozen-lockfile

View File

@@ -19,7 +19,7 @@ jobs:
edit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v4
# headが$GITHUB_REF_NAME, baseが$STABLE_BRANCHかつopenぎPRを1つ取垗
- name: Get PR
run: |

View File

@@ -36,7 +36,7 @@ jobs:
outputs:
pr_number: ${{ steps.get_pr.outputs.pr_number }}
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v4
# headが$GITHUB_REF_NAME, baseが$STABLE_BRANCHかつopenぎPRを1つ取垗
- name: Get PRs
run: |

View File

@@ -16,7 +16,7 @@ jobs:
# api-artifact
steps:
- name: Download artifact
uses: actions/github-script@v9
uses: actions/github-script@v7.0.1
with:
script: |
const fs = require('fs');
@@ -60,7 +60,7 @@ jobs:
- name: Echo full diff
run: cat ./api-full.json.diff
- name: Upload full diff to Artifact
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@v4
with:
name: api-artifact
path: |
@@ -73,9 +73,9 @@ jobs:
HEADER="こぎPRãĢよるapi.jsonãŽåˇŽåˆ†"
FOOTER="[Get diff files from Workflow Page](https://github.com/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID})"
DIFF_BYTES="$(stat ./api.json.diff -c '%s' | tr -d '\n')"
echo "$HEADER" > ./output.md
if (( "$DIFF_BYTES" <= 1 )); then
echo 'åˇŽåˆ†ã¯ã‚ã‚Šãžã›ã‚“ã€‚' >> ./output.md
else
@@ -87,18 +87,18 @@ jobs:
echo '```' >> ./output.md
echo '</details>' >> .output.md
fi
echo "$FOOTER" >> ./output.md
- uses: thollander/actions-comment-pull-request@v3
- uses: thollander/actions-comment-pull-request@v2
with:
pr-number: ${{ steps.load-pr-num.outputs.pr-number }}
comment-tag: show_diff
file-path: ./output.md
pr_number: ${{ steps.load-pr-num.outputs.pr-number }}
comment_tag: show_diff
filePath: ./output.md
- name: Tell error to PR
uses: thollander/actions-comment-pull-request@v3
uses: thollander/actions-comment-pull-request@v2
if: failure() && steps.load-pr-num.outputs.pr-number
with:
pr-number: ${{ steps.load-pr-num.outputs.pr-number }}
comment-tag: show_diff_error
pr_number: ${{ steps.load-pr-num.outputs.pr-number }}
comment_tag: show_diff_error
message: |
api.jsonãŽåˇŽåˆ†äŊœæˆä¸­ãĢエナãƒŧがį™ēį”Ÿã—ãžã—ãŸã€‚čŠŗį´°ã¯[Workflowぎログ](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})をįĸēčĒã—ãĻください。

View File

@@ -1,177 +0,0 @@
name: Report backend memory
on:
workflow_run:
types: [completed]
workflows:
- Get backend memory usage # get-backend-memory.yml
jobs:
compare-memory:
runs-on: ubuntu-latest
if: ${{ github.event.workflow_run.conclusion == 'success' }}
permissions:
pull-requests: write
steps:
- name: Download artifact
uses: actions/github-script@v9
with:
script: |
const fs = require('fs');
let allArtifacts = await github.rest.actions.listWorkflowRunArtifacts({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: context.payload.workflow_run.id,
});
let matchArtifacts = allArtifacts.data.artifacts.filter((artifact) => {
return artifact.name.startsWith("memory-artifact-") || artifact.name == "memory-artifact"
});
await Promise.all(matchArtifacts.map(async (artifact) => {
let download = await github.rest.actions.downloadArtifact({
owner: context.repo.owner,
repo: context.repo.repo,
artifact_id: artifact.id,
archive_format: 'zip',
});
await fs.promises.writeFile(`${process.env.GITHUB_WORKSPACE}/${artifact.name}.zip`, Buffer.from(download.data));
}));
- name: Extract all artifacts
run: |
find . -mindepth 1 -maxdepth 1 -type f -name '*.zip' -exec unzip {} -d artifacts ';'
ls -la artifacts/
- name: Load PR Number
id: load-pr-num
run: echo "pr-number=$(cat artifacts/pr_number)" >> "$GITHUB_OUTPUT"
- name: Output base
run: cat ./artifacts/memory-base.json
- name: Output head
run: cat ./artifacts/memory-head.json
- name: Compare memory usage
id: compare
run: |
BASE_MEMORY=$(cat ./artifacts/memory-base.json)
HEAD_MEMORY=$(cat ./artifacts/memory-head.json)
variation() {
calc() {
BASE=$(echo "$BASE_MEMORY" | jq -r ".${1}.${2} // 0")
HEAD=$(echo "$HEAD_MEMORY" | jq -r ".${1}.${2} // 0")
DIFF=$((HEAD - BASE))
if [ "$BASE" -gt 0 ]; then
DIFF_PERCENT=$(echo "scale=2; ($DIFF * 100) / $BASE" | bc)
else
DIFF_PERCENT=0
fi
# Convert KB to MB for readability
BASE_MB=$(echo "scale=2; $BASE / 1024" | bc)
HEAD_MB=$(echo "scale=2; $HEAD / 1024" | bc)
DIFF_MB=$(echo "scale=2; $DIFF / 1024" | bc)
JSON=$(jq -c -n \
--argjson base "$BASE_MB" \
--argjson head "$HEAD_MB" \
--argjson diff "$DIFF_MB" \
--argjson diff_percent "$DIFF_PERCENT" \
'{base: $base, head: $head, diff: $diff, diff_percent: $diff_percent}')
echo "$JSON"
}
JSON=$(jq -c -n \
--argjson VmRSS "$(calc $1 VmRSS)" \
--argjson VmHWM "$(calc $1 VmHWM)" \
--argjson VmSize "$(calc $1 VmSize)" \
--argjson VmData "$(calc $1 VmData)" \
'{VmRSS: $VmRSS, VmHWM: $VmHWM, VmSize: $VmSize, VmData: $VmData}')
echo "$JSON"
}
JSON=$(jq -c -n \
--argjson beforeGc "$(variation beforeGc)" \
--argjson afterGc "$(variation afterGc)" \
--argjson afterRequest "$(variation afterRequest)" \
'{beforeGc: $beforeGc, afterGc: $afterGc, afterRequest: $afterRequest}')
echo "res=$JSON" >> "$GITHUB_OUTPUT"
- id: build-comment
name: Build memory comment
env:
RES: ${{ steps.compare.outputs.res }}
run: |
HEADER="## Backend memory usage comparison"
FOOTER="[See workflow logs for details](https://github.com/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID})"
echo "$HEADER" > ./output.md
echo >> ./output.md
table() {
echo "| Metric | base (MB) | head (MB) | Diff (MB) | Diff (%) |" >> ./output.md
echo "|--------|------:|------:|------:|------:|" >> ./output.md
line() {
METRIC=$2
BASE=$(echo "$RES" | jq -r ".${1}.${2}.base")
HEAD=$(echo "$RES" | jq -r ".${1}.${2}.head")
DIFF=$(echo "$RES" | jq -r ".${1}.${2}.diff")
DIFF_PERCENT=$(echo "$RES" | jq -r ".${1}.${2}.diff_percent")
if (( $(echo "$DIFF_PERCENT > 0" | bc -l) )); then
DIFF="+$DIFF"
DIFF_PERCENT="+$DIFF_PERCENT"
fi
# highlight VmRSS
if [ "$2" = "VmRSS" ]; then
METRIC="**${METRIC}**"
BASE="**${BASE}**"
HEAD="**${HEAD}**"
DIFF="**${DIFF}**"
DIFF_PERCENT="**${DIFF_PERCENT}**"
fi
echo "| ${METRIC} | ${BASE} MB | ${HEAD} MB | ${DIFF} MB | ${DIFF_PERCENT}% |" >> ./output.md
}
line $1 VmRSS
line $1 VmHWM
line $1 VmSize
line $1 VmData
}
echo "### Before GC" >> ./output.md
table beforeGc
echo >> ./output.md
echo "### After GC" >> ./output.md
table afterGc
echo >> ./output.md
echo "### After Request" >> ./output.md
table afterRequest
echo >> ./output.md
# Determine if this is a significant change (more than 5% increase)
if [ "$(echo "$RES" | jq -r '.afterGc.VmRSS.diff_percent | tonumber > 5')" = "true" ]; then
echo "âš ī¸ **Warning**: Memory usage has increased by more than 5%. Please verify this is not an unintended change." >> ./output.md
echo >> ./output.md
fi
echo "$FOOTER" >> ./output.md
- uses: thollander/actions-comment-pull-request@v3
with:
pr-number: ${{ steps.load-pr-num.outputs.pr-number }}
comment-tag: show_memory_diff
file-path: ./output.md
- name: Tell error to PR
uses: thollander/actions-comment-pull-request@v3
if: failure() && steps.load-pr-num.outputs.pr-number
with:
pr-number: ${{ steps.load-pr-num.outputs.pr-number }}
comment-tag: show_memory_diff_error
message: |
An error occurred while comparing backend memory usage. See [workflow logs](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}) for details.

View File

@@ -1,51 +0,0 @@
name: Request release review
on:
issue_comment:
types: [created]
jobs:
reply:
if: github.event.comment.body == '/request-release-review'
runs-on: ubuntu-latest
permissions:
contents: read
issues: write
pull-requests: write
steps:
- name: Reply
uses: actions/github-script@v9
with:
script: |
const body = `To dev team (@misskey-dev/dev):
ãƒĒãƒĒãƒŧã‚šãŒææĄˆã•ã‚ŒãĻいぞす :rocket:
GOぎ場合はapprove、NO GOãŽå ´åˆã¯ããŽæ—¨ã‚ŗãƒĄãƒŗãƒˆã‚’ãŠéĄ˜ã„ã„ãŸã—ãžã™ã€‚
判断ãĢã‚ãŸãŖãĻč€ƒæ…Žã™ãšãčĻŗį‚šã¯ã€
- やり掋したことはãĒいかīŧŸ
- CHANGELOGは過不čļŗãĒいかīŧŸ
- バãƒŧã‚¸ãƒ§ãƒŗãĢå•éĄŒã¯ãĒいかīŧŸ(æœˆčˇ¨ã„ã§ã„ã‚‹ãŽãĢ更新åŋ˜ã‚ŒãĻいるãĒお)
- å†č€ƒã™ãšãä앿§˜ãƒģåŽŸčŖ…ã¯ãĒいかīŧŸ
- ベãƒŧã‚ŋį‰ˆã‚’æ¤œč¨ŧしたã‚ĩãƒŧバãƒŧã‹ã‚‰ä¸å…ˇåˆãŽå ąå‘Šį­‰ã¯ä¸ŠãŒãŖãĻãĒいかīŧŸ
- (ã‚ģキãƒĨãƒĒãƒ†ã‚ŖãŽäŋŽæ­Ŗã‚„重čρãĒバグäŋŽæ­ŖãĒおぎため)ãƒĒãƒĒãƒŧ゚をæ€Ĩã„ã æ–šãŒč‰¯ã„ã‹īŧŸãã†ã§ã¯ãĒいかīŧŸ
- ActionsがčŊãĄãĻいãĒいかīŧŸ
ãĒおが挙げられぞす。
ご協力ありがとうございぞす :sparkles:
`
const issue_number = context.payload.issue ? context.payload.issue.number : (context.payload.pull_request && context.payload.pull_request.number)
if (!issue_number) {
console.log('No issue or PR number found in payload; skipping')
} else {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number,
body,
})
}

View File

@@ -5,6 +5,7 @@ on:
branches:
- master
- develop
- dev/storybook8 # for testing
pull_request_target:
branches-ignore:
# Since pull requests targets master mostly is the "develop" branch.
@@ -14,7 +15,7 @@ on:
jobs:
build:
# Chromatic is not likely to be available for fork repositories, so we disable for fork repositories.
# chromatic is not likely to be available for fork repositories, so we disable for fork repositories.
if: github.repository == 'misskey-dev/misskey'
runs-on: ubuntu-latest
@@ -22,12 +23,12 @@ jobs:
NODE_OPTIONS: "--max_old_space_size=7168"
steps:
- uses: actions/checkout@v6.0.2
- uses: actions/checkout@v4.2.2
if: github.event_name != 'pull_request_target'
with:
fetch-depth: 0
submodules: true
- uses: actions/checkout@v6.0.2
- uses: actions/checkout@v4.2.2
if: github.event_name == 'pull_request_target'
with:
fetch-depth: 0
@@ -35,19 +36,22 @@ jobs:
ref: "refs/pull/${{ github.event.number }}/merge"
- name: Checkout actual HEAD
if: github.event_name == 'pull_request_target'
run: git checkout "$(git rev-list --parents -n1 HEAD | cut -d" " -f3)"
id: rev
run: |
echo "base=$(git rev-list --parents -n1 HEAD | cut -d" " -f2)" >> $GITHUB_OUTPUT
git checkout $(git rev-list --parents -n1 HEAD | cut -d" " -f3)
- name: Setup pnpm
uses: pnpm/action-setup@v6.0.3
- name: Use Node.js
uses: actions/setup-node@v6.4.0
uses: pnpm/action-setup@v4.1.0
- name: Use Node.js 20.x
uses: actions/setup-node@v4.2.0
with:
node-version-file: '.node-version'
cache: 'pnpm'
- run: pnpm i --frozen-lockfile
- name: Check pnpm-lock.yaml
run: git diff --exit-code pnpm-lock.yaml
- name: Build dependent packages
run: pnpm -F misskey-js -F misskey-bubble-game -F misskey-reversi build
- name: Build misskey-js
run: pnpm --filter misskey-js build
- name: Build storybook
run: pnpm --filter frontend build-storybook
- name: Publish to Chromatic
@@ -78,19 +82,24 @@ jobs:
if: github.event_name == 'pull_request_target'
id: chromatic_pull_request
run: |
CHROMATIC_PARAMETER="$(node packages/frontend/.storybook/changes.js $(git diff --name-only origin/${GITHUB_BASE_REF}...origin/${GITHUB_HEAD_REF} | xargs))"
DIFF="${{ steps.rev.outputs.base }} HEAD"
if [ "$DIFF" = "0000000000000000000000000000000000000000 HEAD" ]; then
DIFF="HEAD"
fi
CHROMATIC_PARAMETER="$(node packages/frontend/.storybook/changes.js $(git diff-tree --no-commit-id --name-only -r $(echo "$DIFF") | xargs))"
if [ "$CHROMATIC_PARAMETER" = " --skip" ]; then
echo "skip=true" >> $GITHUB_OUTPUT
fi
BRANCH="${{ github.event.pull_request.head.user.login }}:$GITHUB_HEAD_REF"
if [ "$BRANCH" = "misskey-dev:$GITHUB_HEAD_REF" ]; then
BRANCH="$GITHUB_HEAD_REF"
BRANCH="${{ github.event.pull_request.head.user.login }}:$HEAD_REF"
if [ "$BRANCH" = "misskey-dev:$HEAD_REF" ]; then
BRANCH="$HEAD_REF"
fi
pnpm --filter frontend chromatic --exit-once-uploaded -d storybook-static --branch-name "$BRANCH" $(echo "$CHROMATIC_PARAMETER")
env:
HEAD_REF: ${{ github.event.pull_request.head.ref }}
CHROMATIC_PROJECT_TOKEN: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
- name: Notify that Chromatic detects changes
uses: actions/github-script@v9
uses: actions/github-script@v7.0.1
if: github.event_name != 'pull_request_target' && steps.chromatic_push.outputs.success == 'false'
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
@@ -102,7 +111,7 @@ jobs:
body: 'Chromatic detects changes. Please [review the changes on Chromatic](https://www.chromatic.com/builds?appId=6428f7d7b962f0b79f97d6e4).'
})
- name: Upload Artifacts
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@v4
with:
name: storybook
path: packages/frontend/storybook-static

View File

@@ -18,66 +18,35 @@ on:
- packages/misskey-js/**
- .github/workflows/test-backend.yml
- .github/misskey/test.yml
workflow_dispatch:
inputs:
force_ffmpeg_cache_update:
description: 'Force update ffmpeg cache'
required: false
default: false
type: boolean
jobs:
unit:
name: Unit tests (backend)
runs-on: ubuntu-latest
strategy:
matrix:
node-version-file:
- .node-version
- .github/min.node-version
node-version: [22.11.0]
services:
postgres:
image: postgres:18
image: postgres:15
ports:
- 54312:5432
env:
POSTGRES_DB: test-misskey
POSTGRES_HOST_AUTH_METHOD: trust
redis:
image: redis:8
image: redis:7
ports:
- 56312:6379
meilisearch:
image: getmeili/meilisearch:v1.42.1
ports:
- 57712:7700
env:
MEILI_NO_ANALYTICS: true
MEILI_ENV: development
steps:
- uses: actions/checkout@v6.0.2
- uses: actions/checkout@v4.2.2
with:
submodules: true
- name: Setup pnpm
uses: pnpm/action-setup@v6.0.3
- name: Get current date
id: current-date
run: echo "today=$(date +'%Y-%m-%d')" >> $GITHUB_OUTPUT
- name: Setup and Restore ffmpeg/ffprobe Cache
id: cache-ffmpeg
uses: actions/cache@v5
with:
path: |
/usr/local/bin/ffmpeg
/usr/local/bin/ffprobe
# daily cache
key: ${{ runner.os }}-ffmpeg-${{ steps.current-date.outputs.today }}
restore-keys: |
${{ runner.os }}-ffmpeg-${{ steps.current-date.outputs.today }}
uses: pnpm/action-setup@v4.1.0
- name: Install FFmpeg
if: steps.cache-ffmpeg.outputs.cache-hit != 'true' || github.event.inputs.force_ffmpeg_cache_update == true
run: |
for i in {1..3}; do
echo "Attempt $i: Installing FFmpeg..."
@@ -92,10 +61,10 @@ jobs:
exit 1
fi
done
- name: Use Node.js
uses: actions/setup-node@v6.4.0
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4.2.0
with:
node-version-file: ${{ matrix.node-version-file }}
node-version: ${{ matrix.node-version }}
cache: 'pnpm'
- run: pnpm i --frozen-lockfile
- name: Check pnpm-lock.yaml
@@ -107,7 +76,7 @@ jobs:
- name: Test
run: pnpm --filter backend test-and-coverage
- name: Upload to Codecov
uses: codecov/codecov-action@v6
uses: codecov/codecov-action@v5
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: ./packages/backend/coverage/coverage-final.json
@@ -115,36 +84,34 @@ jobs:
e2e:
name: E2E tests (backend)
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
node-version-file:
- .node-version
- .github/min.node-version
node-version: [22.11.0]
services:
postgres:
image: postgres:18
image: postgres:15
ports:
- 54312:5432
env:
POSTGRES_DB: test-misskey
POSTGRES_HOST_AUTH_METHOD: trust
redis:
image: redis:8
image: redis:7
ports:
- 56312:6379
steps:
- uses: actions/checkout@v6.0.2
- uses: actions/checkout@v4.2.2
with:
submodules: true
- name: Setup pnpm
uses: pnpm/action-setup@v6.0.3
- name: Use Node.js
uses: actions/setup-node@v6.4.0
uses: pnpm/action-setup@v4.1.0
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4.2.0
with:
node-version-file: ${{ matrix.node-version-file }}
node-version: ${{ matrix.node-version }}
cache: 'pnpm'
- run: pnpm i --frozen-lockfile
- name: Check pnpm-lock.yaml
@@ -156,51 +123,7 @@ jobs:
- name: Test
run: pnpm --filter backend test-and-coverage:e2e
- name: Upload to Codecov
uses: codecov/codecov-action@v6
uses: codecov/codecov-action@v5
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: ./packages/backend/coverage/coverage-final.json
migration:
name: Migration tests (backend)
runs-on: ubuntu-latest
strategy:
matrix:
node-version-file:
- .node-version
#- .github/min.node-version
services:
postgres:
image: postgres:18
ports:
- 54312:5432
env:
POSTGRES_DB: test-misskey
POSTGRES_HOST_AUTH_METHOD: trust
steps:
- uses: actions/checkout@v6.0.2
with:
submodules: true
- name: Setup pnpm
uses: pnpm/action-setup@v6.0.3
- name: Get current date
id: current-date
run: echo "today=$(date +'%Y-%m-%d')" >> $GITHUB_OUTPUT
- name: Use Node.js
uses: actions/setup-node@v6.4.0
with:
node-version-file: ${{ matrix.node-version-file }}
cache: 'pnpm'
- run: pnpm i --frozen-lockfile
- name: Check pnpm-lock.yaml
run: git diff --exit-code pnpm-lock.yaml
- name: Copy Configure
run: cp .github/misskey/test.yml .config
- name: Build
run: pnpm build
- name: Run migrations
run: MISSKEY_CONFIG_YML=test.yml pnpm --filter backend migrate
- name: Check no migrations are remaining
run: MISSKEY_CONFIG_YML=test.yml pnpm --filter backend check-migrations

View File

@@ -14,13 +14,6 @@ on:
- packages/backend/**
- packages/misskey-js/**
- .github/workflows/test-federation.yml
workflow_dispatch:
inputs:
force_ffmpeg_cache_update:
description: 'Force update ffmpeg cache'
required: false
default: false
type: boolean
jobs:
test:
@@ -28,31 +21,14 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
node-version-file:
- .node-version
- .github/min.node-version
node-version: [22.11.0]
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v4
with:
submodules: true
- name: Setup pnpm
uses: pnpm/action-setup@v6.0.3
- name: Get current date
id: current-date
run: echo "today=$(date +'%Y-%m-%d')" >> $GITHUB_OUTPUT
- name: Setup and Restore ffmpeg/ffprobe Cache
id: cache-ffmpeg
uses: actions/cache@v5
with:
path: |
/usr/local/bin/ffmpeg
/usr/local/bin/ffprobe
# daily cache
key: ${{ runner.os }}-ffmpeg-${{ steps.current-date.outputs.today }}
restore-keys: |
${{ runner.os }}-ffmpeg-${{ steps.current-date.outputs.today }}
uses: pnpm/action-setup@v4.1.0
- name: Install FFmpeg
if: steps.cache-ffmpeg.outputs.cache-hit != 'true' || github.event.inputs.force_ffmpeg_cache_update == true
run: |
for i in {1..3}; do
echo "Attempt $i: Installing FFmpeg..."
@@ -67,10 +43,10 @@ jobs:
exit 1
fi
done
- name: Use Node.js
uses: actions/setup-node@v6.4.0
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4.2.0
with:
node-version-file: ${{ matrix.node-version-file }}
node-version: ${{ matrix.node-version }}
cache: 'pnpm'
- name: Build Misskey
run: |
@@ -78,7 +54,6 @@ jobs:
pnpm build
- name: Setup
run: |
echo "NODE_VERSION=$(cat ${{ matrix.node-version-file }})" >> $GITHUB_ENV
cd packages/backend/test-federation
bash ./setup.sh
sudo chmod 644 ./certificates/*.test.key
@@ -96,16 +71,18 @@ jobs:
docker compose logs | tail -n 300
exit 1
- name: Test
id: test
continue-on-error: true
run: |
cd packages/backend/test-federation
docker compose run --no-deps tester
- name: Log
if: always()
if: ${{ steps.test.outcome == 'failure' }}
run: |
cd packages/backend/test-federation
docker compose logs
exit 1
- name: Stop servers
if: always()
run: |
cd packages/backend/test-federation
docker compose down

View File

@@ -27,16 +27,20 @@ jobs:
name: Unit tests (frontend)
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [22.11.0]
steps:
- uses: actions/checkout@v6.0.2
- uses: actions/checkout@v4.2.2
with:
submodules: true
- name: Setup pnpm
uses: pnpm/action-setup@v6.0.3
- name: Use Node.js
uses: actions/setup-node@v6.4.0
uses: pnpm/action-setup@v4.1.0
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4.2.0
with:
node-version-file: '.node-version'
node-version: ${{ matrix.node-version }}
cache: 'pnpm'
- run: pnpm i --frozen-lockfile
- name: Check pnpm-lock.yaml
@@ -48,7 +52,7 @@ jobs:
- name: Test
run: pnpm --filter frontend test-and-coverage
- name: Upload Coverage
uses: codecov/codecov-action@v6
uses: codecov/codecov-action@v5
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: ./packages/frontend/coverage/coverage-final.json
@@ -60,23 +64,24 @@ jobs:
strategy:
fail-fast: false
matrix:
node-version: [22.11.0]
browser: [chrome]
services:
postgres:
image: postgres:18
image: postgres:15
ports:
- 54312:5432
env:
POSTGRES_DB: test-misskey
POSTGRES_HOST_AUTH_METHOD: trust
redis:
image: redis:8
image: redis:7
ports:
- 56312:6379
steps:
- uses: actions/checkout@v6.0.2
- uses: actions/checkout@v4.2.2
with:
submodules: true
# https://github.com/cypress-io/cypress-docker-images/issues/150
@@ -86,11 +91,11 @@ jobs:
#- uses: browser-actions/setup-firefox@latest
# if: ${{ matrix.browser == 'firefox' }}
- name: Setup pnpm
uses: pnpm/action-setup@v6.0.3
- name: Use Node.js
uses: actions/setup-node@v6.4.0
uses: pnpm/action-setup@v4.1.0
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4.2.0
with:
node-version-file: '.node-version'
node-version: ${{ matrix.node-version }}
cache: 'pnpm'
- run: pnpm i --frozen-lockfile
- name: Copy Configure
@@ -105,7 +110,7 @@ jobs:
- name: Cypress install
run: pnpm exec cypress install
- name: Cypress run
uses: cypress-io/github-action@v7.1.9
uses: cypress-io/github-action@v6
timeout-minutes: 15
with:
install: false
@@ -113,12 +118,12 @@ jobs:
wait-on: 'http://localhost:61812'
headed: true
browser: ${{ matrix.browser }}
- uses: actions/upload-artifact@v7
- uses: actions/upload-artifact@v4
if: failure()
with:
name: ${{ matrix.browser }}-cypress-screenshots
path: cypress/screenshots
- uses: actions/upload-artifact@v7
- uses: actions/upload-artifact@v4
if: always()
with:
name: ${{ matrix.browser }}-cypress-videos

View File

@@ -20,17 +20,22 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [22.11.0]
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
steps:
- name: Checkout
uses: actions/checkout@v6.0.2
uses: actions/checkout@v4.2.2
- name: Setup pnpm
uses: pnpm/action-setup@v6.0.3
uses: pnpm/action-setup@v4.1.0
- name: Setup Node.js
uses: actions/setup-node@v6.4.0
- name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4.2.0
with:
node-version-file: '.node-version'
node-version: ${{ matrix.node-version }}
cache: 'pnpm'
- name: Install dependencies
@@ -48,7 +53,7 @@ jobs:
CI: true
- name: Upload Coverage
uses: codecov/codecov-action@v6
uses: codecov/codecov-action@v5
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: ./packages/misskey-js/coverage/coverage-final.json

View File

@@ -15,16 +15,20 @@ jobs:
name: Production build
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [22.11.0]
steps:
- uses: actions/checkout@v6.0.2
- uses: actions/checkout@v4.2.2
with:
submodules: true
- name: Setup pnpm
uses: pnpm/action-setup@v6.0.3
- name: Use Node.js
uses: actions/setup-node@v6.4.0
uses: pnpm/action-setup@v4.1.0
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4.2.0
with:
node-version-file: '.node-version'
node-version: ${{ matrix.node-version }}
cache: 'pnpm'
- run: pnpm i --frozen-lockfile
- name: Check pnpm-lock.yaml

View File

@@ -16,16 +16,20 @@ jobs:
validate-api-json:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [22.11.0]
steps:
- uses: actions/checkout@v6.0.2
- uses: actions/checkout@v4.2.2
with:
submodules: true
- name: Setup pnpm
uses: pnpm/action-setup@v6.0.3
- name: Use Node.js
uses: actions/setup-node@v6.4.0
uses: pnpm/action-setup@v4.1.0
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4.2.0
with:
node-version-file: '.node-version'
node-version: ${{ matrix.node-version }}
cache: 'pnpm'
- name: Install Redocly CLI
run: npm i -g @redocly/cli

1
.gitignore vendored
View File

@@ -46,7 +46,6 @@ docker-compose.yml
built
built-test
js-built
src-js
/data
/.cache-loader
/db

3
.gitmodules vendored
View File

@@ -0,0 +1,3 @@
[submodule "fluent-emojis"]
path = fluent-emojis
url = https://github.com/misskey-dev/emojis.git

View File

@@ -1 +1 @@
22.15.0
22.11.0

3
.npmrc Normal file
View File

@@ -0,0 +1,3 @@
engine-strict = true
save-exact = true
shell-emulator = true

View File

@@ -3,16 +3,11 @@
"**/node_modules": true
},
"typescript.tsdk": "node_modules/typescript/lib",
"typescript.enablePromptUseWorkspaceTsdk": true,
"files.associations": {
"*.test.ts": "typescript"
},
"jest.jestCommandLine": "pnpm run jest",
"jest.runMode": "on-demand",
"jest.virtualFolders": [
{ "name": "backend unit", "jestCommandLine": "pnpm -F backend run test" },
{ "name": "backend e2e", "jestCommandLine": "pnpm -F backend run test:e2e"},
{ "name": "misskey-js", "jestCommandLine": "pnpm -F misskey-js run jest" }
],
"editor.codeActionsOnSave": {
"source.fixAll": "explicit"
},

139
AGENTS.md
View File

@@ -1,139 +0,0 @@
# Misskey – AI Agent Guide
ã“ãŽãƒ•ã‚Ąã‚¤ãƒĢは Misskey ãƒĒポジトãƒĒで動く AI ã‚ŗãƒŧãƒ‡ã‚Ŗãƒŗã‚°ã‚¨ãƒŧã‚¸ã‚§ãƒŗãƒˆ (Claude Code / OpenAI Codex / GitHub Copilot į­‰) ãŒå…ąé€šã§å‚į…§ã™ã‚‹ **最äŊŽé™ãŽãƒĢãƒŧãƒĢとį´ĸåŧ•**。æŦĄãŽ 3 įĩŒčˇ¯ã‹ã‚‰å‚į…§ãƒģčĒ­ãŋčžŧãŋされる:
- **Claude Code**: ãƒĢãƒŧト `CLAUDE.md` から `@AGENTS.md` で取りčžŧぞれる
- **OpenAI Codex**: ãƒĢãƒŧト `AGENTS.md` ã‚’į›´æŽĨčĒ­ãŋčžŧむ
- **GitHub Copilot**: `.github/copilot-instructions.md` (æœŦãƒ•ã‚Ąã‚¤ãƒĢã‚’å‚į…§ã—ã¤ã¤ã€Copilot code review 向けãĢåŋ…é ˆčĻį´„ã‚’å†æŽ˛ã™ã‚‹ãƒ•ã‚Ąã‚¤ãƒĢ) įĩŒį”ąã§å‚į…§ã™ã‚‹
äēē間 contributor 向けぎ一čˆŦčĻį´„ (Issue / PR ぎå‡ēし斚、ActivityPub æ‹ĄåŧĩãĒお) は [CONTRIBUTING.md](CONTRIBUTING.md) ã‚’å‚į…§ã€‚æœŦãƒ•ã‚Ąã‚¤ãƒĢは AI が **ã‚ŗãƒŧドを書くãƒģį›´ã™** 際ãĢ踏ãŋ外しãĻはいけãĒいäē‹é …ãĢįĩžãŖãĻいる。
---
## ä狿•…į›´įĩãƒĢãƒŧãƒĢ (åŋ…ず厈る)
違反すると CI å¤ąæ•—ãžãŸã¯æœŦį•Ēä狿•…ãĢãĒる。順厈すること。
### 1. SPDX ヘッダãƒŧåŋ…é ˆ
AGPL-3.0-only įŽĄčŊ„かつ SPDX CI å¯žčąĄãƒ‡ã‚ŖãƒŦクトãƒĒãĢ新čĻ `.ts` / `.js` / `.cjs` / `.mjs` / `.vue` / `.scss` / `.html` ãƒ•ã‚Ąã‚¤ãƒĢをčŋŊ加する場合、冒頭ãĢäģĨ下をåŋ…ずäģ˜ã‘る。æŦ čŊすると CI (`spdx` ジョブ) ãŒå¤ąæ•—ã™ã‚‹ã€‚CI ãŽå¯žčąĄåˆ¤åŽšã¯ [.github/workflows/check-spdx-license-id.yml](.github/workflows/check-spdx-license-id.yml) ぎ `directories` é…åˆ—ã‚’å‚į…§ (`*.config.{ts,js,cjs,mjs}` と `*eslint*` は除外)。
`packages/misskey-js` は MIT ナイã‚ģãƒŗã‚šãŽã‚ĩãƒ–ãƒ‘ãƒƒã‚ąãƒŧジãĒぎで、こぎ AGPL ヘッダãƒŧを一型ãĢäģ˜ã‘ãĒい。ã‚ĩãƒ–ãƒ‘ãƒƒã‚ąãƒŧジå›ē有ぎ `package.json` / `LICENSE` / æ—ĸå­˜ãƒ•ã‚Ąã‚¤ãƒĢぎヘッダãƒŧãĢ垓う。
`.ts` / `.js` / `.cjs` / `.mjs` / `.scss`:
```text
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
```
`.vue` / `.html` (HTML ã‚ŗãƒĄãƒŗãƒˆåŊĸåŧ):
```text
<!--
SPDX-FileCopyrightText: syuilo and misskey-project
SPDX-License-Identifier: AGPL-3.0-only
-->
```
### 2. locales/*.yml は `ja-JP.yml` ぎãŋįˇ¨é›†å¯
`locales/` 配下ぎ YAML は **`ja-JP.yml` ぎãŋæ‰‹å‹•įˇ¨é›†ã—ãĻよい**。äģ–言čĒžãƒ•ã‚Ąã‚¤ãƒĢ (`en-US.yml` į­‰) は Crowdin ぎč‡Ē動配äŋĄå…ˆã§ã€æ‰‹å‹•įˇ¨é›†ã™ã‚‹ã¨ä¸Šæ›¸ãã§å¤ąã‚ã‚Œã‚‹ã€‚æ šæ‹ : `locales/README.md` (ja-JP.yml äģĨå¤–ã‚’æ‰‹å‹•įˇ¨é›†ã—ãĒã„é‹į”¨) と `crowdin.yml` (`ja-JP.yml` → `locales/%locale%.yml` ãŽåŒæœŸč¨­åŽš)。
### 3. マãƒŧジ済ãŋ migration をįĩļ寞ãĢįˇ¨é›†ã—ãĒい
`packages/backend/migration/{unixMs}-{PascalName}.js` ãŽã†ãĄã€æ—ĸãĢ `develop` / `master` ãĢマãƒŧジ済ãŋãŽãƒ•ã‚Ąã‚¤ãƒĢは **įĩļ寞ãĢ変更しãĒい**。æœŦį•Ēį’°åĸƒã§åąĨ歴攚変がčĩˇãã‚‹ã¨æˇąåˆģãĒデãƒŧã‚ŋ不整合をåŧ•きčĩˇã“す。
゚キãƒŧマ変更がåŋ…čρãĒ場合は **新しいã‚ŋイム゚ã‚ŋãƒŗãƒ—ã§æ–°čĻãƒ•ã‚Ąã‚¤ãƒĢ** をäŊœæˆã™ã‚‹:
- ãƒ•ã‚Ąã‚¤ãƒĢ名: `node -e "console.log(Date.now())"` で UNIX ms を取垗し、`{ms}-<descriptive-name>.js` としãĻįŊŽãã€‚å‘Ŋ名゚ã‚ŋイãƒĢはæ—ĸ存åąĨæ­´ã§æˇˇåœ¨ã—ãĻおり (`1716129964060-ChannelIdDenormalizedForMiPoll.js` ぎようãĒ PascalCase、`1721666053703-fixDriveUrl.js` ぎようãĒ camelCase、`1672704136584-remove-latestStatus.js` ぎようãĒ kebab-case)ã€å¤‰æ›´ã‚’čĄ¨ã™å˜ä¸€ãŽč‹ąčĒžåã§ã‚ã‚Œã°č‰¯ã„ã€‚ã‚¯ãƒŠã‚šåå´ã¯ PascalCase + 13 æĄã‚ŋイム゚ã‚ŋãƒŗãƒ— (`class FixDriveUrl1721666053703 { ... }`) をåŋ…ず厈ること。
- `up()` と `down()` ãŽä¸Ąæ–šã‚’åŋ…ãšåŽŸčŖ…ã™ã‚‹ (`down` は `up` ぎ厌全ãĒåˇģきæˆģし)。
- `pnpm --filter backend check-migrations` を通す。これは **TypeORM schema builder で pending DDL を検å‡ēする** 検æŸģ ([packages/backend/scripts/check_migrations_clean.js](packages/backend/scripts/check_migrations_clean.js))ã€‚ã‚¨ãƒŗãƒ†ã‚Ŗãƒ†ã‚ŖãŽ `@Column` / `@Entity` 変更が migration ãĢ取りčžŧぞれãĻいãĒいとここで検å‡ēされる。ã‚ŋイム゚ã‚ŋãƒŗãƒ—ãŽé †åēč‡ĒäŊ“ã‚’į›´æŽĨ検æŸģするわけではãĒい (順åēãŒåŖŠã‚ŒãŸå ´åˆãŽå¤ąæ•—はåˆĨįĩŒčˇ¯ã§å‡ēる)。
ã‚¨ãƒŗãƒ†ã‚Ŗãƒ†ã‚ŖåˇŽåˆ†ã‹ã‚‰ TypeORM CLI でč‡Ēå‹•į”Ÿæˆã—ãŸã„ / `CREATE INDEX CONCURRENTLY` į­‰ãŽã‚Ēãƒ—ã‚ˇãƒ§ãƒŗã‚’äŊŋいたい場合は [.claude/skills/create-migration/SKILL.md](.claude/skills/create-migration/SKILL.md) ã‚’å‚į…§ã€‚æ‰‹æ›¸ã / CLI ãŠãĄã‚‰ãŽæ–šåŧã§ã‚‚ä¸Šč¨˜ 3 į‚š (åąĨ歴攚変įρæ­ĸ / `up`+`down` / `check-migrations`) がæē€ãŸã›ã‚Œã°č‰¯ã„。
---
## åŋ…é ˆã‚ŗãƒžãƒŗãƒ‰
| ᔍ途 | ã‚ŗãƒžãƒŗãƒ‰ |
| --- | --- |
| 全äŊ“ビãƒĢド | `pnpm build` |
| 開į™ēã‚ĩãƒŧバãƒŧ (backend + frontend watch) | `pnpm dev` |
| Lint (typecheck + eslint, å…¨ãƒ‘ãƒƒã‚ąãƒŧジ) | `pnpm lint` (= `pnpm --no-bail -r lint`ã€‚æœ€åˆãŽå¤ąæ•—ã§æ­ĸãžã‚‰ãšå…¨ãƒ‘ãƒƒã‚ąãƒŧジぎįĩæžœã‚’収集する) |
| Backend unit test (Vitest) | `pnpm --filter backend test` |
| Backend e2e test | `pnpm --filter backend test:e2e` |
| Backend federation test | `pnpm --filter backend test:fed` |
| Frontend test (Vitest) | `pnpm --filter frontend test` |
| Cypress E2E (čρ `start:test`) | `pnpm e2e` |
| Storybook dev (frontend) | `pnpm --filter frontend storybook-dev` |
| Migration éŠį”¨ | `pnpm migrate` |
| Migration ロãƒŧãƒĢバック | `pnpm revert` |
| Migration ぎ pending DDL 検æŸģ (ã‚¨ãƒŗãƒ†ã‚Ŗãƒ†ã‚ŖåˇŽåˆ†ãŽå–ã‚Ščžŧãŋæŧã‚Œæ¤œå‡ē) | `pnpm --filter backend check-migrations` |
| `misskey-js` å†į”Ÿæˆ (API 変更垌åŋ…é ˆ) | `pnpm build-misskey-js-with-types` |
> Backend ぎ TypeScript 型チェックは `pnpm --filter backend typecheck` (tsgo)。
> 個åˆĨãƒ•ã‚Ąã‚¤ãƒĢへぎ ESLint --fix は `pnpm exec eslint --fix <path>`。
> **backend テ゚ト (`test` / `test:e2e` / `test:fed`) åŽŸčĄŒå‰ãĢ `.config/test.yml` がåŋ…čρ** (æœĒäŊœæˆã ã¨ãƒ†ã‚šãƒˆč‡ĒäŊ“がčĩˇå‹•しãĒい)ã€‚ã‚ŗãƒ”ãƒŧæ‰‹é †ã¨čŠŗį´°ã¯ [.claude/docs/testing.md §Backend 全čˆŦぎ前提](.claude/docs/testing.md#backend-全čˆŦぎ前提-configtestyml) ã‚’å‚į…§ã€‚
---
## CHANGELOG
ãƒĻãƒŧã‚ļãƒŧåŊąéŸŋぎある変更 (抟čƒŊčŋŊ加ãƒģäŋŽæ­Ŗãƒģ攚善) は `CHANGELOG.md` ぎ冒頭 `## Unreleased` ã‚ģã‚¯ã‚ˇãƒ§ãƒŗãĢ 1 行čŋŊ加する。ãƒĒãƒ•ã‚Ąã‚¯ã‚ŋãƒĒãƒŗã‚°į­‰ãŽå†…éƒ¨å¤‰æ›´ã¯ä¸čĻã€‚
### ã‚ģã‚¯ã‚ˇãƒ§ãƒŗæ§‹é€ 
`## Unreleased` 配下ãĢ **3 つぎã‚ĩブã‚ģã‚¯ã‚ˇãƒ§ãƒŗ** ãŒį”¨æ„ã•ã‚ŒãĻいる:
- `### General` — å…ąé€š / æ¨Ēæ–­įš„ãĒ変更
- `### Client` — `packages/frontend` įŗģ
- `### Server` — `packages/backend` įŗģ
### ã‚¨ãƒŗãƒˆãƒĒ書åŧ
芲åŊ“ã‚ĩブã‚ģã‚¯ã‚ˇãƒ§ãƒŗãĢ `- <Prefix>: <æĻ‚čρ>` ぎåŊĸåŧã§čŋŊ加。Prefix は先頭大文字。
```text
- Enhance: ノãƒŧãƒˆãŽčŠŗį´°čĄ¨į¤ēでぎå…Ŧé–‹į¯„å›˛ãŽčĄ¨į¤ēを攚善
- Fix: 通įŸĨãŒį´„10᧒遅åģļã™ã‚‹å•éĄŒã‚’äŋŽæ­Ŗ
- Feat: 新抟čƒŊぎčŋŊ加
```
### č§ĻãŖãĻはいけãĒã„į¯„å›˛
- `## Unreleased` **äģĨ外** ぎã‚ģã‚¯ã‚ˇãƒ§ãƒŗ (過åŽģãƒĒãƒĒãƒŧ゚) は変更しãĒい。
- `## Unreleased` ぎčĻ‹å‡ēしと 3 つぎįŠēã‚ĩブã‚ģã‚¯ã‚ˇãƒ§ãƒŗéǍæ ŧč‡ĒäŊ“はįļ­æŒã™ã‚‹ (ãƒĒãƒĒãƒŧ゚゚クãƒĒプトが期垅する構造)。
> å‚č€ƒ: ã‚ŗãƒŸãƒƒãƒˆãƒĄãƒƒã‚ģãƒŧジ側は `enhance(frontend): ...` / `fix(backend): ...` ぎ小文字 + ã‚šã‚ŗãƒŧプåŊĸåŧ ([CONTRIBUTING.md](CONTRIBUTING.md) å‚į…§)。CHANGELOG とは書åŧãŒį•°ãĒã‚‹į‚šãĢæŗ¨æ„ã€‚
---
## ã‚Ēãƒŗãƒ‡ãƒžãƒŗãƒ‰å‚į…§ (åŋ…čĻæ™‚ãĢ Read すること)
äģĨ下は AI が **äŊœæĨ­å¯žčąĄãĢåŋœã˜ãĻåŋ…čρãĒときだけ** é–‹ãčŠŗį´°ãƒ‰ã‚­ãƒĨãƒĄãƒŗãƒˆã€‚å¸¸æ™‚ã‚ŗãƒŗãƒ†ã‚­ã‚šãƒˆãĢはčŧ‰ã›ãĒい。
| äŊ•をしたい時 | å‚į…§å…ˆ |
| --- | --- |
| ãƒ‘ãƒƒã‚ąãƒŧジ構成ãƒģ䞝存é–ĸäŋ‚ã‚’æŠŠæĄã—ãŸã„ | [.claude/docs/architecture.md](.claude/docs/architecture.md) |
| `packages/backend` ã‚’įˇ¨é›†ã™ã‚‹ (NestJS / TypeORM / migration / API endpoint) | [.claude/docs/backend.md](.claude/docs/backend.md) |
| `packages/frontend` ã‚’įˇ¨é›†ã™ã‚‹ (Vue 3 / Mk* / i18n / SCSS module / `os.ts`) | [.claude/docs/frontend.md](.claude/docs/frontend.md) |
| テ゚トを書くãƒģčĩ°ã‚‰ã›ã‚‹ (Vitest / Cypress / Storybook) | [.claude/docs/testing.md](.claude/docs/testing.md) |
| 有劚化済 Claude Code ãƒ—ãƒŠã‚°ã‚¤ãƒŗãŽį”¨é€”ã‚’įĸēčĒ | [.claude/docs/plugins.md](.claude/docs/plugins.md) |
---
## ツãƒŧãƒĢå›ēæœ‰ãŽčŖœåŠŠãƒ•ã‚Ąã‚¤ãƒĢ
`.claude/` 配下は Claude Code å›ē有ぎ skills / agents / slash commands ã‚’é›†į´„ã—ãĻいる (Codex / Copilot はčĒ­ãŋéŖ›ã°ã—ãĻよい):
- `.claude/skills/` — įš°ã‚Ščŋ”しã‚ŋã‚šã‚¯į”¨ãŽ skill åŽšįžŠ (例: `add-api-endpoint`, `create-migration`)
- `.claude/agents/` — 専門ãƒŦビãƒĨãƒŧエãƒŧã‚¸ã‚§ãƒŗãƒˆ (例: `misskey-api-reviewer`, `vue-component-reviewer`)
- `.claude/commands/` — Claude Code ãŽã‚šãƒŠãƒƒã‚ˇãƒĨã‚ŗãƒžãƒŗãƒ‰ (例: `/check-misskey-js`, `/changelog-add`)
- `.claude/docs/` — ã‚Ēãƒŗãƒ‡ãƒžãƒŗãƒ‰å‚į…§ãƒ‰ã‚­ãƒĨãƒĄãƒŗãƒˆ (ä¸Šč¨˜ãŽčĄ¨ã§į¤ēしたもぎ。Codex / Copilot からも内厚č‡ĒäŊ“はčĒ­ã‚ã‚‹)
- `.claude/settings.json` — Claude Code ãŽæœ‰åŠšãƒ—ãƒŠã‚°ã‚¤ãƒŗ (`enabledPlugins`) ぎãŋã‚’č¨˜čŧ‰ã—ãŸå…ąæœ‰č¨­åŽšã€‚hook ã¯æ„å›ŗįš„ãĢį™ģéŒ˛ã—ãĒい (各 contributor が `.claude/settings.local.json` で opt-in する斚針)
- `.claude/settings.local.json` — 個äēēロãƒŧã‚ĢãƒĢč¨­åŽš (`.gitignore` 済)
ã‚ĩãƒŧドパãƒŧãƒ†ã‚Ŗį”ąæĨ (everything-claude-code į”ąæĨぎ MIT ナイã‚ģãƒŗã‚šãƒ•ã‚Ąã‚¤ãƒĢį­‰) ぎå‡ē典は [.claude/THIRD_PARTY_LICENSES.md](.claude/THIRD_PARTY_LICENSES.md) ã‚’å‚į…§ã€‚

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +0,0 @@
# Misskey – Claude Code Guide
ãƒĢãƒŧãƒĢæœŦäŊ“は [AGENTS.md](AGENTS.md) (Codex / Copilot ã¨å…ąæœ‰ã™ã‚‹å˜ä¸€ã‚Ŋãƒŧ゚)。æœŦãƒ•ã‚Ąã‚¤ãƒĢは Claude Code į”¨ãŽč–„ã„ãƒŠãƒƒãƒ‘ãƒŧで、`@AGENTS.md` 構文でæœŦäŊ“čĻį´„ã‚’ã‚ģãƒƒã‚ˇãƒ§ãƒŗé–‹å§‹æ™‚ãĢã‚ŗãƒŗãƒ†ã‚­ã‚šãƒˆã¸åą•é–‹ã™ã‚‹ã€‚
Claude Code å›ēæœ‰ãŽčŖœåŠŠ (skills / agents / slash commands / docs) は `.claude/` 配下ãĢã‚ŗãƒŸãƒƒãƒˆæ¸ˆã€‚å€‹äēēロãƒŧã‚ĢãƒĢč¨­åŽšã¯ `.claude/settings.local.json` ãĢ、MCP čĒč¨ŧæƒ…å ąã¯ `.claude/.credentials.json` ãĢįŊŽã (いずれも `.gitignore` 済)。
@AGENTS.md

View File

@@ -189,14 +189,6 @@ pnpm migrate
After finishing the migration, you can proceed.
#### Cloudflare tunnel
Cloudflare tunnelをäŊŋうとロãƒŧã‚ĢãƒĢぎMisskeyã‚ĩãƒŧバãƒŧã‚’ã‚¤ãƒŗã‚ŋãƒŧネットãĢå…Ŧ開できぞす。
HTTPSでしか動äŊœã—ãĒい抟čƒŊを検č¨ŧしたい時や、゚マホãĒおåˆĨぎデバイ゚からロãƒŧã‚ĢãƒĢぎMisskeyã‚ĩãƒŧバãƒŧを検č¨ŧしたい時ãĢäžŋ刊です。
##### Cloudflare warpとäŊĩį”¨ã™ã‚‹éš›ãŽtips
> cloudflared (Cloudflare Tunnel) は region1.v2.argotunnel.com / region2.v2.argotunnel.com ãĢ QUIC/HTTP2 でã‚ĸã‚Ļトバã‚Ļãƒŗãƒ‰æŽĨįļšã™ã‚‹ãŽã§ã™ãŒã€WARP ã‚’æœ‰åŠšåŒ–ã™ã‚‹ã¨ã“ãŽãƒˆãƒŠãƒ•ã‚Ŗãƒƒã‚¯ãŒ WARP įĩŒį”ąãĢãĒãŖãĻãƒĢãƒŧプ/切断しぞす。これら 2 ポトを WARP ãŽãƒˆãƒŗãƒãƒĢ除外īŧˆsplit tunnelīŧ‰ãĢčŋŊ加することで、cloudflared だけは WARP をバイパ゚しãĻį›´æŽĨ Cloudflare エッジへæŽĨįļšã§ãã‚‹ã‚ˆã†ãĢãĒりぞす。
### Start developing
During development, it is useful to use the
```
@@ -266,12 +258,6 @@ Misskey uses Vue(v3) as its front-end framework.
- **When creating a new component, please use the Composition API (with [setup sugar](https://v3.vuejs.org/api/sfc-script-setup.html) and [ref sugar](https://github.com/vuejs/rfcs/discussions/369)) instead of the Options API.**
- Some of the existing components are implemented in the Options API, but it is an old implementation. Refactors that migrate those components to the Composition API are also welcome.
## Tabler Icons
ã‚ĸã‚¤ã‚ŗãƒŗã¯ã€Production Build時ãĢäŊŋį”¨ã•ã‚ŒãĻいãĒいもぎが削除されるようãĢãĒãŖãĻいぞす。
**ã‚ĸã‚¤ã‚ŗãƒŗã‚’å‹•įš„ãĢč¨­åŽšã™ã‚‹éš›ãĢは、 `ti-${someVal}` ぎようãĒ、ã‚ĸã‚¤ã‚ŗãƒŗåãŽãŋã‚’å‹•įš„ãĢå¤‰åŒ–ã•ã›ã‚‹åŽŸčŖ…ã‚’čĄŒã‚ãĒいでください。**
åŋ…ず `ti-xxx` ぎようãĒ厌全ãĒクナ゚名をåĢめるようãĢしãĻください。
## nirax
niraxは、MisskeyでäŊŋį”¨ã—ãĻいるã‚ĒãƒĒジナãƒĢãŽãƒ•ãƒ­ãƒŗãƒˆã‚¨ãƒŗãƒ‰ãƒĢãƒŧãƒ†ã‚Ŗãƒŗã‚°ã‚ˇã‚šãƒ†ãƒ ã§ã™ã€‚
**vue-routerからåŊąéŸŋを多大ãĢ受けãĻいるぎで、ぞずはvue-routerãĢついãĻå­Ļãļことをお勧めしぞす。**
@@ -287,6 +273,7 @@ niraxは、MisskeyでäŊŋį”¨ã—ãĻいるã‚ĒãƒĒジナãƒĢãŽãƒ•ãƒ­ãƒŗãƒˆã‚¨ãƒŗãƒ‰
query?: Record<string, string>;
loginRequired?: boolean;
hash?: string;
globalCacheKey?: string;
children?: RouteDef[];
}
```
@@ -583,12 +570,32 @@ enumぎ列挙ぎ内厚ぎ削除は、そぎ値をもつãƒŦã‚ŗãƒŧドを全ãĻ削
### MigrationäŊœæˆæ–šæŗ•
packages/backendで:
```sh
pnpm dlx typeorm migration:generate -d ormconfig.js -o --esm <migration name>
pnpm dlx typeorm migration:generate -d ormconfig.js -o <migration name>
```
- į”ŸæˆåžŒã€ãƒ•ã‚Ąã‚¤ãƒĢをmigration下ãĢį§ģしãĻください
- äŊœæˆã•れた゚クãƒĒプトは不åŋ…čρãĒ変更をåĢむため除åŽģしãĻください
- `-o` (`--outputJs`) で JS åŊĸåŧã€`--esm` で ESM åŊĸåŧãĢį”Ÿæˆã™ã‚‹ã€‚Misskey ぎæ—ĸ存 migration はすずãĻ ESM JS ãĒãŽã§ä¸Ąæ–šãŽã‚Ēãƒ—ã‚ˇãƒ§ãƒŗãŒåŋ…čρ
### JSON SchemaぎobjectでanyOfをäŊŋうとき
JSON Schemaで、objectãĢ寞しãĻanyOfをäŊŋう場合、anyOfぎ中でpropertiesã‚’åŽšįžŠã—ãĒいこと。
バãƒĒデãƒŧã‚ˇãƒ§ãƒŗãŒåŠšã‹ãĒいため。īŧˆSchemaTypeもそぎようãĢäŊœã‚‰ã‚ŒãĻおり、objectぎanyOf内ぎpropertiesは捨ãĻられぞすīŧ‰
https://github.com/misskey-dev/misskey/pull/10082
テキ゚トhogeãŠã‚ˆãŗfugaãĢついãĻã€į‰‡æ–šã‚’åŋ…é ˆã¨ã—ã¤ã¤ä¸Ąæ–šãŽæŒ‡åŽšã‚‚ã‚ã‚Šã†ã‚‹å ´åˆ:
```ts
export const paramDef = {
type: 'object',
properties: {
hoge: { type: 'string', minLength: 1 },
fuga: { type: 'string', minLength: 1 },
},
anyOf: [
{ required: ['hoge'] },
{ required: ['fuga'] },
],
} as const;
```
### ã‚ŗãƒã‚¯ã‚ˇãƒ§ãƒŗãĢは`markRaw`せよ
**VueãŽã‚ŗãƒŗãƒãƒŧãƒãƒŗãƒˆãŽdataã‚Ēãƒ—ã‚ˇãƒ§ãƒŗã¨ã—ãĻ**misskey.jsãŽã‚ŗãƒã‚¯ã‚ˇãƒ§ãƒŗã‚’č¨­åŽšã™ã‚‹ã¨ãã€åŋ…ず`markRaw`でナップしãĻãã ã•ã„ã€‚ã‚¤ãƒŗã‚šã‚ŋãƒŗã‚šãŒä¸åŋ…čρãĢãƒĒã‚ĸã‚¯ãƒ†ã‚Ŗãƒ–åŒ–ã•ã‚Œã‚‹ã“ã¨ã§ã€misskey.js内ぎå‡Ļį†ã§ä¸å…ˇåˆãŒį™ēį”Ÿã™ã‚‹ã¨ã¨ã‚‚ãĢ、パフりãƒŧãƒžãƒŗã‚šä¸ŠãŽå•éĄŒãĢã‚‚įš‹ãŒã‚‹ã€‚ãĒお、Composition APIをäŊŋう場合はこぎ限りではãĒい(ãƒĒã‚ĸã‚¯ãƒ†ã‚Ŗãƒ–åŒ–ã¯ãƒžãƒ‹ãƒĨã‚ĸãƒĢãĒため)。
@@ -627,23 +634,3 @@ color: hsl(from var(--MI_THEME-accent) h s calc(l - 10));
color: color(from var(--MI_THEME-accent) srgb r g b / 0.5);
```
## č€ƒãˆæ–š
### DRYãĢ囚われるãĒ
åŋ…čρãĒぎは一čˆŦ化ではãĒくæŠŊčąĄåŒ–ã¨č€ƒãˆãžã™ã€‚
ᛞäŋĄã›ãšã€čĒ¤ãŖãŸãƒģ不åŋ…čρãĒå…ąé€šåŒ–ã¯éŋけ、それがč‡Ēį„ļã ã¨æ„Ÿã˜ã‚‹å ´åˆã¯é‡č¤‡ã•ã›ã‚‹å‹‡æ°—ã‚’æŒãĄãžã—ã‚‡ã†ã€‚
### Misskeyã‚’č¤‡é›‘ãĢしãĒã„åŽŸčŖ…
ãã‚ŒãŒã„ãã‚‰č¤‡é›‘ã§ã‚ãŖãĻも、Misskeyå›ēæœ‰ãŽã‚ŗãƒŗãƒ†ã‚­ã‚šãƒˆã¨é–ĸåŋƒãŒåˆ†é›ĸされãĻいる(もしくはäē‹åŽŸä¸Šåˆ†é›ĸされãĻいるとčĻ‹åšã™ã“ã¨ãŒã§ãã‚‹)åŽŸčŖ…ã§ã‚ã‚Œã°ã€ãã‚Œã¯MisskeyãŽã‚ŗãƒŧドベãƒŧ゚ãĢå¯žã™ã‚‹č¤‡é›‘æ€§ãĢåŊąéŸŋを与えãĒã„ã¨č€ƒãˆãžã™ã€‚
䞋えるãĒら、VueやAiScriptã¨ã„ãŖãŸMisskeyがäŊŋį”¨ã—ãĻいるナイブナãƒĒãŽå†…éƒ¨åŽŸčŖ…ãŒã„ãã‚‰č¤‡é›‘ã ãŖãŸã¨ã—ãĻも、「それをäŊŋį”¨ã—ãĻいるからMisskeyãŽåŽŸčŖ…ã¯č¤‡é›‘ã§ã‚ã‚‹ã€ã¨ã„ã†ã“ã¨ãĢはãĒらãĒいぎと同じです。
MisskeyãŽãƒ‰ãƒĄã‚¤ãƒŗįŸĨč­˜ã‹ã‚‰é–ĸåŋƒãŒåˆ†é›ĸされãĻいるということは、MisskeyãŽåŽŸčŖ…ãĢついãĻč€ƒãˆã‚‹æ™‚ãĢãã‚Œã‚‰ãŽå†…éƒ¨åŽŸčŖ…ã‚’č€ƒæ…Žã™ã‚‹åŋ…čĻãŒį„Ąãã€čĒįŸĨč˛ čˇã‚’åĸ—やさãĒいからです。
ぞた重čρãĒį‚šã¯ã€ããŽåŽŸčŖ…ãŒã€MisskeyãƒĒポジトãƒĒぎ外部ãĢあるかãƒģ内部ãĢあるかということや、MisskeyãŒãƒĄãƒŗãƒ†ãƒŠãƒŗã‚šã™ã‚‹ã‚‚ãŽã‹ãƒģįŦŦä¸‰č€…ãŒãƒĄãƒŗãƒ†ãƒŠãƒŗã‚šã™ã‚‹ã‚‚ãŽã‹ã¨ã„ãŖãŸã“ã¨ã¯č¤‡é›‘æ€§ã‚’č€ƒãˆã‚‹ä¸Šã§ã¯ãģã¨ã‚“ãŠį„ĄčĻ–ã§ãã‚‹ã¨ã„ã†į‚šã§ã™ã€‚
ã‚‚ãĄã‚ã‚“ããŽåŽŸčŖ…ãŒMisskeyãƒĒポジトãƒĒãĢあり、MisskeyãŒãƒĄãƒŗãƒ†ãƒŠãƒŗã‚šã—ãĒければãĒらãĒいもぎは、äŋåŽˆãŽã‚ŗã‚šãƒˆã¯ã‹ã‹ã‚Šãžã™ã€‚
しかし、MisskeyぎæœŦčŗĒįš„ãĒ設計ãƒģåŽŸčŖ…ã¨ã„ã†čĻŗį‚šã§čĻ‹ãŸã¨ãã¯ã€ããŽåŽŸčŖ…ã¯åŽŸčŗĒįš„ãĢ外部ナイブナãƒĒぎようãĢæŒ¯ã‚‹čˆžã„ãžã™ã€‚
æ›č¨€ã™ã‚Œã°ã€ŒãŸãžãŸãžMisskeyぎ開į™ēč€…ã¨åŒã˜äēēãŸãĄãŒãƒĄãƒŗãƒ†ãƒŠãƒŗã‚šã—ãĻいるし、たぞたぞMisskeyぎãƒĒポジトãƒĒ内ãĢįŊŽã„ãĻあるだけぎ外部ナイブナãƒĒ」です。
ããŽãŸã‚ã€åŽŸčŖ…ã‚’ãĒるずくMisskeyãŽãƒ‰ãƒĄã‚¤ãƒŗįŸĨč­˜ã‹ã‚‰į‹ŦįĢ‹ã—ãŸã‚‚ãŽãĢすれば、MisskeyãŽã‚ŗãƒŧドベãƒŧã‚šãŽč¤‡é›‘æ€§ã‚’ä¸Šã’ã‚‹ã“ã¨ãĒく抟čƒŊåŽŸčŖ…ã‚’čĄŒã†ã“ã¨ãŒã§ãã€ãŠåž—ã§ã‚ã‚‹ã¨č¨€ãˆãžã™ã€‚
ã‚‚ãĄã‚ã‚“ãã‚ŒãĢã“ã ã‚ãŖãĻ、äē›į´°ãĒåŽŸčŖ…ã§ã‚‚ããŽã‚ˆã†ãĢ分é›ĸしãĻã—ãžã†ã¨ã‹ãˆãŖãĻčĒįŸĨč˛ čˇãŒåĸ—ãˆãŸã‚Šã€åŽŸčŖ…é‡ãŒåĸ—えãĻãƒĄãƒĒãƒƒãƒˆã‚’ãƒ‡ãƒĄãƒĒãƒƒãƒˆãŒä¸Šå›žã‚‹å ´åˆã‚‚ã‚ã‚‹ãŽã§ã€ã‚ąãƒŧã‚šãƒã‚¤ã‚ąãƒŧ゚ではありぞす。

View File

@@ -1,8 +1,15 @@
Unless otherwise stated this repository is
Copyright Š 2014-2026 syuilo and contributors
Copyright Š 2014-2025 syuilo and contributors
And is distributed under The GNU Affero General Public License Version 3, you should have received a copy of the license file as LICENSE.
Misskey includes several third-party Open-Source softwares.
Emoji keywords for Unicode 11 and below by Mu-An Chiou
License: MIT
https://github.com/muan/emojilib/blob/master/LICENSE
RsaSignature2017 implementation by Transmute Industries Inc
License: MIT
https://github.com/transmute-industries/RsaSignature2017/blob/master/LICENSE

View File

@@ -1,6 +1,6 @@
# syntax = docker/dockerfile:1.23
# syntax = docker/dockerfile:1.4
ARG NODE_VERSION=22.22.2-bookworm
ARG NODE_VERSION=22.11.0-bookworm
# build assets & compile TypeScript
@@ -18,14 +18,10 @@ WORKDIR /misskey
COPY --link ["pnpm-lock.yaml", "pnpm-workspace.yaml", "package.json", "./"]
COPY --link ["scripts", "./scripts"]
COPY --link ["patches", "./patches"]
COPY --link ["packages/backend/package.json", "./packages/backend/"]
COPY --link ["packages/frontend-shared/package.json", "./packages/frontend-shared/"]
COPY --link ["packages/frontend/package.json", "./packages/frontend/"]
COPY --link ["packages/frontend-embed/package.json", "./packages/frontend-embed/"]
COPY --link ["packages/frontend-builder/package.json", "./packages/frontend-builder/"]
COPY --link ["packages/i18n/package.json", "./packages/i18n/"]
COPY --link ["packages/icons-subsetter/package.json", "./packages/icons-subsetter/"]
COPY --link ["packages/sw/package.json", "./packages/sw/"]
COPY --link ["packages/misskey-js/package.json", "./packages/misskey-js/"]
COPY --link ["packages/misskey-reversi/package.json", "./packages/misskey-reversi/"]
@@ -56,7 +52,6 @@ WORKDIR /misskey
COPY --link ["pnpm-lock.yaml", "pnpm-workspace.yaml", "package.json", "./"]
COPY --link ["scripts", "./scripts"]
COPY --link ["patches", "./patches"]
COPY --link ["packages/backend/package.json", "./packages/backend/"]
COPY --link ["packages/misskey-js/package.json", "./packages/misskey-js/"]
COPY --link ["packages/misskey-reversi/package.json", "./packages/misskey-reversi/"]
@@ -74,8 +69,6 @@ FROM --platform=$TARGETPLATFORM node:${NODE_VERSION}-slim AS runner
ARG UID="991"
ARG GID="991"
ENV PNPM_CONFIG_VERIFY_DEPS_BEFORE_RUN=false
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
ffmpeg tini curl libjemalloc-dev libjemalloc2 \
@@ -104,7 +97,7 @@ COPY --chown=misskey:misskey --from=native-builder /misskey/packages/misskey-js/
COPY --chown=misskey:misskey --from=native-builder /misskey/packages/misskey-reversi/built ./packages/misskey-reversi/built
COPY --chown=misskey:misskey --from=native-builder /misskey/packages/misskey-bubble-game/built ./packages/misskey-bubble-game/built
COPY --chown=misskey:misskey --from=native-builder /misskey/packages/backend/built ./packages/backend/built
COPY --chown=misskey:misskey --from=native-builder /misskey/packages/i18n/built ./packages/i18n/built
COPY --chown=misskey:misskey --from=native-builder /misskey/fluent-emojis /misskey/fluent-emojis
COPY --chown=misskey:misskey . ./
ENV LD_PRELOAD=/usr/local/lib/libjemalloc.so

View File

@@ -24,10 +24,6 @@
<a href="https://www.patreon.com/syuilo">
<img src="https://custom-icon-badges.herokuapp.com/badge/become_a-patron-F96854?logoColor=F96854&style=for-the-badge&logo=patreon&labelColor=363B40" alt="become a patron"/></a>
[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/misskey-dev/misskey)
<a href="https://flatt.tech/oss/gmo/trampoline" target="_blank"><img src="https://flatt.tech/assets/images/badges/gmo-oss.svg" height="24px"/></a>
</div>
## Thanks
@@ -51,13 +47,3 @@ Thanks to [Crowdin](https://crowdin.com/) for providing the localization platfor
<a href="https://hub.docker.com/"><img src="https://user-images.githubusercontent.com/20679825/230148221-f8e73a32-a49b-47c3-9029-9a15c3824f92.png" height="30" alt="Docker" /></a>
Thanks to [Docker](https://hub.docker.com/) for providing the container platform that helps us run Misskey in production.
---
<div align="center">
Support us with a ⭐ !
[![Star History Chart](https://api.star-history.com/svg?repos=misskey-dev/misskey&type=Date)](https://star-history.com/#misskey-dev/misskey&Date)
</div>

View File

@@ -6,7 +6,7 @@ Also, the later tasks are more indefinite and are subject to change as developme
This is the phase we are at now. We need to make a high-maintenance environment that can withstand future development.
- ~~Make the number of type errors zero (backend)~~ → Done âœ”ī¸
- ~~Make the number of type errors zero (frontend)~~ → Done âœ”ī¸
- Make the number of type errors zero (frontend)
- Improve CI
- ~~Fix tests~~ → Done âœ”ī¸
- Fix random test failures - https://github.com/misskey-dev/misskey/issues/7985 and https://github.com/misskey-dev/misskey/issues/7986

BIN
assets/about/drive.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

BIN
assets/about/post.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 317 KiB

BIN
assets/about/reaction.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

BIN
assets/about/ui.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 KiB

BIN
assets/ss/explore.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 238 KiB

BIN
assets/ss/user.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 KiB

Binary file not shown.

View File

@@ -173,11 +173,6 @@ id: "aidx"
# dsn: 'https://examplePublicKey@o0.ingest.sentry.io/0'
#sentryForFrontend:
# vueIntegration:
# tracingOptions:
# trackComponents: true
# browserTracingIntegration:
# replayIntegration:
# options:
# dsn: 'https://examplePublicKey@o0.ingest.sentry.io/0'
@@ -190,9 +185,6 @@ id: "aidx"
# Number of worker processes
#clusterLimit: 1
# Number of threads of extra thread pool for CPU-intensive tasks (per worker)
#threadPoolSize: 1
# Job concurrency per worker
# deliverJobConcurrency: 128
# inboxJobConcurrency: 16
@@ -224,6 +216,9 @@ id: "aidx"
# Media Proxy
#mediaProxy: https://example.com/proxy
# Sign to ActivityPub GET request (default: true)
signToActivityPubGet: true
#allowedPrivateNetworks: [
# '127.0.0.1/32'
#]

View File

@@ -27,7 +27,7 @@ spec:
ports:
- containerPort: 3000
- name: postgres
image: postgres:18-alpine
image: postgres:15-alpine
env:
- name: POSTGRES_USER
value: "example-misskey-user"

View File

@@ -15,13 +15,13 @@ services:
db:
restart: always
image: postgres:18-alpine
image: postgres:15-alpine
ports:
- "5432:5432"
env_file:
- .config/docker.env
volumes:
- ./db:/var/lib/postgresql
- ./db:/var/lib/postgresql/data
healthcheck:
test: "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"
interval: 5s

View File

@@ -37,13 +37,13 @@ services:
db:
restart: always
image: postgres:18-alpine
image: postgres:15-alpine
networks:
- internal_network
env_file:
- .config/docker.env
volumes:
- ./db:/var/lib/postgresql
- ./db:/var/lib/postgresql/data
healthcheck:
test: "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"
interval: 5s

View File

@@ -2,6 +2,11 @@ import { defineConfig } from 'cypress'
export default defineConfig({
e2e: {
// We've imported your old cypress plugins here.
// You may want to clean this up later by importing these.
setupNodeEvents(on, config) {
return require('./cypress/plugins/index.js')(on, config)
},
baseUrl: 'http://localhost:61812',
},
})

View File

@@ -31,14 +31,6 @@ describe('Before setup instance', () => {
// ãĒぜか動かãĒい
//cy.wait('@signup').should('have.property', 'response.statusCode');
cy.wait('@signup');
cy.intercept('POST', '/api/admin/update-meta').as('update-meta');
cy.get('[data-cy-next]').click();
cy.get('[data-cy-server-name] input').type('Testskey');
cy.get('[data-cy-server-setup-wizard-apply]').click();
cy.wait('@update-meta');
});
});
@@ -78,8 +70,6 @@ describe('After setup instance', () => {
cy.get('[data-cy-signup-password] input').type('alice1234');
cy.get('[data-cy-signup-submit]').should('be.disabled');
cy.get('[data-cy-signup-password-retype] input').type('alice1234');
cy.get('[data-cy-signup-submit]').should('be.disabled');
cy.get('[data-cy-signup-invitation-code] input').type('test-invitation-code');
cy.get('[data-cy-signup-submit]').should('not.be.disabled');
cy.get('[data-cy-signup-submit]').click();

22
cypress/plugins/index.js Normal file
View File

@@ -0,0 +1,22 @@
/// <reference types="cypress" />
// ***********************************************************
// This example plugins/index.js can be used to load plugins
//
// You can change the location of this file or turn off loading
// the plugins file with the 'pluginsFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/plugins-guide
// ***********************************************************
// This function is called when a project is opened or re-opened (e.g. due to
// the project's config changing)
/**
* @type {Cypress.PluginConfig}
*/
// eslint-disable-next-line no-unused-vars
module.exports = (on, config) => {
// `on` is used to hook into various events Cypress emits
// `config` is the resolved Cypress config
}

View File

@@ -1,7 +1,7 @@
{
"compilerOptions": {
"lib": ["dom"],
"target": "esnext",
"lib": ["dom", "es5"],
"target": "es5",
"types": ["cypress", "node"]
},
"include": ["./**/*.ts"]

1
fluent-emojis Submodule

Submodule fluent-emojis added at cae981eb4c

View File

@@ -4,8 +4,8 @@
*/
/* eslint-disable @typescript-eslint/explicit-function-return-type */
import { action } from 'storybook/actions';
import type { StoryObj } from '@storybook/vue3';
import { action } from '@storybook/addon-actions';
import { StoryObj } from '@storybook/vue3';
import { HttpResponse, http } from 'msw';
import { abuseUserReport } from '../packages/frontend/.storybook/fakes.js';
import { commonHandlers } from '../packages/frontend/.storybook/mocks.js';

View File

@@ -1,232 +0,0 @@
<!--
SPDX-FileCopyrightText: syuilo and misskey-project
SPDX-License-Identifier: AGPL-3.0-only
-->
<template>
<canvas ref="canvasEl" style="display: block; width: 100%; height: 100%; pointer-events: none;"></canvas>
</template>
<script lang="ts" setup>
import { onMounted, onUnmounted, useTemplateRef } from 'vue';
import isChromatic from 'chromatic/isChromatic';
import { initShaderProgram } from '@/utility/webgl.js';
const VERTEX_SHADER = `#version 300 es
in vec2 position;
out vec2 in_uv;
void main() {
in_uv = (position + 1.0) / 2.0;
gl_Position = vec4(position, 0.0, 1.0);
}
`;
const FRAGMENT_SHADER = `#version 300 es
precision mediump float;
const float PI = 3.141592653589793;
const float TWO_PI = 6.283185307179586;
const float HALF_PI = 1.5707963267948966;
in vec2 in_uv;
uniform vec2 in_resolution;
uniform float u_scale;
uniform float u_time;
uniform float u_seed;
uniform float u_angle;
uniform float u_radius;
uniform vec3 u_color;
uniform vec2 u_ripplePositions[16];
uniform float u_rippleRadiuses[16];
out vec4 out_color;
float getRipple(vec2 uv) {
float strength = 0.0;
float thickness = 0.05;
for (int i = 0; i < 16; i++) {
if (u_rippleRadiuses[i] <= 0.0) continue;
float d = distance(uv, u_ripplePositions[i]);
// フチ
if (d < u_rippleRadiuses[i] + thickness && d > u_rippleRadiuses[i] - thickness) {
float gradate = abs(d - u_rippleRadiuses[i] + thickness) / thickness;
strength += (1.0 - u_rippleRadiuses[i]) * gradate;
}
// 内側
if (d < u_rippleRadiuses[i] + thickness) {
strength += 0.25 * (1.0 - u_rippleRadiuses[i]);
}
}
return strength;
}
void main() {
float x_ratio = min(in_resolution.x / in_resolution.y, 1.0);
float y_ratio = min(in_resolution.y / in_resolution.x, 1.0);
float angle = -(u_angle * PI);
vec2 centeredUv = (in_uv - vec2(0.5, 0.5)) * vec2(x_ratio, y_ratio);
vec2 rotatedUV = vec2(
centeredUv.x * cos(angle) - centeredUv.y * sin(angle),
centeredUv.x * sin(angle) + centeredUv.y * cos(angle)
);
vec2 uv = rotatedUV;
float time = u_time * 0.00025;
float size = 1.0 / u_scale;
float size_half = size / 2.0;
float modX = mod(uv.x, size);
float modY = mod(uv.y, size);
vec2 pixelated_uv = vec2(
(size * (floor((uv.x - 0.5 - size) / size) + 0.5)),
(size * (floor((uv.y - 0.5 - size) / size) + 0.5))
) + vec2(0.5 + size, 0.5 + size);
float strength = getRipple(pixelated_uv);
float opacity = min(max(strength, 0.0), 1.0);
float threshold = ((u_radius / 2.0) / u_scale);
if (length(vec2(modX - size_half, modY - size_half)) < threshold) {
out_color = vec4(u_color.r, u_color.g, u_color.b, opacity);
//out_color = vec4(1.0);
return;
}
// debug
//float a = min(max(getRipple(uv), 0.0), 1.0);
//out_color = vec4(u_color.r, u_color.g, u_color.b, (opacity + a) / 2.0);
out_color = vec4(0.0, 0.0, 0.0, 0.0);
}
`;
const canvasEl = useTemplateRef('canvasEl');
const props = withDefaults(defineProps<{
scale?: number;
}>(), {
scale: 48,
});
let handle: ReturnType<typeof window['requestAnimationFrame']> | null = null;
onMounted(() => {
const canvas = canvasEl.value!;
let width = canvas.offsetWidth;
let height = canvas.offsetHeight;
canvas.width = width;
canvas.height = height;
const maybeGl = canvas.getContext('webgl2', { preserveDrawingBuffer: false, alpha: true, premultipliedAlpha: false, antialias: true });
if (maybeGl == null) return;
const gl = maybeGl;
const VERTICES = new Float32Array([-1, -1, -1, 1, 1, 1, -1, -1, 1, 1, 1, -1]);
const vertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, VERTICES, gl.STATIC_DRAW);
//gl.clearColor(0.0, 0.0, 0.0, 0.0);
//gl.clear(gl.COLOR_BUFFER_BIT);
const shaderProgram = initShaderProgram(gl, VERTEX_SHADER, FRAGMENT_SHADER);
gl.useProgram(shaderProgram);
const positionLocation = gl.getAttribLocation(shaderProgram, 'position');
gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(positionLocation);
const in_resolution = gl.getUniformLocation(shaderProgram, 'in_resolution');
gl.uniform2fv(in_resolution, [canvas.width, canvas.height]);
const u_time = gl.getUniformLocation(shaderProgram, 'u_time');
const u_seed = gl.getUniformLocation(shaderProgram, 'u_seed');
const u_scale = gl.getUniformLocation(shaderProgram, 'u_scale');
const u_angle = gl.getUniformLocation(shaderProgram, 'u_angle');
const u_radius = gl.getUniformLocation(shaderProgram, 'u_radius');
const u_color = gl.getUniformLocation(shaderProgram, 'u_color');
gl.uniform1f(u_seed, Math.random() * 1000);
gl.uniform1f(u_scale, props.scale);
gl.uniform1f(u_angle, 0.0);
gl.uniform1f(u_radius, 0.15);
gl.uniform3fv(u_color, [0.5, 1.0, 0]);
if (isChromatic()) {
gl.uniform1f(u_time, 0);
gl.drawArrays(gl.TRIANGLES, 0, 6);
} else {
let ripples = [] as { position: [number, number]; startTime: number; }[];
const LIFE_TIME = 1000 * 4;
function render(timeStamp: number) {
let sizeChanged = false;
if (Math.abs(height - canvas.offsetHeight) > 2) {
height = canvas.offsetHeight;
canvas.height = height;
sizeChanged = true;
}
if (Math.abs(width - canvas.offsetWidth) > 2) {
width = canvas.offsetWidth;
canvas.width = width;
sizeChanged = true;
}
if (sizeChanged && gl) {
gl.uniform2fv(in_resolution, [width, height]);
gl.viewport(0, 0, width, height);
}
gl.uniform1f(u_time, timeStamp);
if (Math.random() < 0.01 && ripples.length < 16) {
ripples.push({ position: [(Math.random() * 2) - 1, (Math.random() * 2) - 1], startTime: timeStamp });
}
for (let i = 0; i < 16; i++) {
const o = gl.getUniformLocation(shaderProgram, `u_ripplePositions[${i.toString()}]`);
const r = gl.getUniformLocation(shaderProgram, `u_rippleRadiuses[${i.toString()}]`);
const ripple = ripples[i];
if (ripple == null) {
gl.uniform2f(o, 0, 0);
gl.uniform1f(r, 0.0);
continue;
}
const delta = timeStamp - ripple.startTime;
gl.uniform2f(o, ripple.position[0], ripple.position[1]);
gl.uniform1f(r, delta / LIFE_TIME);
}
ripples = ripples.filter(r => (timeStamp - r.startTime) < LIFE_TIME);
if (ripples.length === 0) {
ripples.push({ position: [(Math.random() * 2) - 1, (Math.random() * 2) - 1], startTime: timeStamp });
}
gl.drawArrays(gl.TRIANGLES, 0, 6);
handle = window.requestAnimationFrame(render);
}
handle = window.requestAnimationFrame(render);
}
});
onUnmounted(() => {
if (handle) {
window.cancelAnimationFrame(handle);
}
// TODO: WebGLãƒĒã‚Ŋãƒŧã‚šãŽč§Ŗæ”ž
});
</script>
<style lang="scss" module>
</style>

View File

@@ -1,190 +0,0 @@
<!--
SPDX-FileCopyrightText: syuilo and misskey-project
SPDX-License-Identifier: AGPL-3.0-only
-->
<template>
<canvas ref="canvasEl" style="display: block; width: 100%; height: 100%; pointer-events: none;"></canvas>
</template>
<script lang="ts" setup>
import { onMounted, onUnmounted, useTemplateRef } from 'vue';
import isChromatic from 'chromatic/isChromatic';
import { GLSL_LIB_SNOISE, initShaderProgram } from '@/utility/webgl.js';
const VERTEX_SHADER = `#version 300 es
in vec2 position;
out vec2 in_uv;
void main() {
in_uv = (position + 1.0) / 2.0;
gl_Position = vec4(position, 0.0, 1.0);
}
`;
const FRAGMENT_SHADER = `#version 300 es
precision mediump float;
const float PI = 3.141592653589793;
const float TWO_PI = 6.283185307179586;
const float HALF_PI = 1.5707963267948966;
${GLSL_LIB_SNOISE}
in vec2 in_uv;
uniform vec2 in_resolution;
uniform float u_scale;
uniform float u_time;
uniform float u_seed;
uniform float u_angle;
uniform float u_radius;
uniform vec3 u_color;
out vec4 out_color;
void main() {
float x_ratio = min(in_resolution.x / in_resolution.y, 1.0);
float y_ratio = min(in_resolution.y / in_resolution.x, 1.0);
float size = 1.0 / u_scale;
float size_half = size / 2.0;
float angle = -(u_angle * PI);
vec2 centeredUv = (in_uv - vec2(0.5, 0.5)) * vec2(x_ratio, y_ratio);
vec2 rotatedUV = vec2(
centeredUv.x * cos(angle) - centeredUv.y * sin(angle),
centeredUv.x * sin(angle) + centeredUv.y * cos(angle)
);
vec2 uv = rotatedUV;
float modX = mod(uv.x, size);
float modY = mod(uv.y, size);
vec2 pixelated_uv = vec2(
(size * (floor((uv.x - 0.5 - size) / size) + 0.5)),
(size * (floor((uv.y - 0.5 - size) / size) + 0.5))
) + vec2(0.5 + size, 0.5 + size);
float time = u_time * 0.00025;
float noiseAScale = 1.0;
float noiseAX = (pixelated_uv.x + u_seed) * (u_scale / noiseAScale);
float noiseAY = (pixelated_uv.y + u_seed) * (u_scale / noiseAScale);
float noiseA = snoise(vec3(noiseAX, noiseAY, time * 2.0));
float noiseBScale = 32.0;
float noiseBX = (pixelated_uv.x + u_seed) * (u_scale / noiseBScale);
float noiseBY = (pixelated_uv.y + u_seed) * (u_scale / noiseBScale);
float noiseB = snoise(vec3(noiseBX, noiseBY, time));
float strength = 0.0;
strength += noiseA * 0.2;
strength += noiseB * 0.8;
float opacity = min(max(strength, 0.0), 1.0);
float threshold = ((u_radius / 2.0) / u_scale);
if (length(vec2(modX - size_half, modY - size_half)) < threshold) {
out_color = vec4(u_color.r, u_color.g, u_color.b, opacity);
return;
}
out_color = vec4(0.0, 0.0, 0.0, 0.0);
}
`;
const canvasEl = useTemplateRef('canvasEl');
const props = withDefaults(defineProps<{
scale?: number;
}>(), {
scale: 48,
});
let handle: ReturnType<typeof window['requestAnimationFrame']> | null = null;
onMounted(() => {
const canvas = canvasEl.value!;
let width = canvas.offsetWidth;
let height = canvas.offsetHeight;
canvas.width = width;
canvas.height = height;
const maybeGl = canvas.getContext('webgl2', { preserveDrawingBuffer: false, alpha: true, premultipliedAlpha: false, antialias: true });
if (maybeGl == null) return;
const gl = maybeGl;
const VERTICES = new Float32Array([-1, -1, -1, 1, 1, 1, -1, -1, 1, 1, 1, -1]);
const vertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, VERTICES, gl.STATIC_DRAW);
//gl.clearColor(0.0, 0.0, 0.0, 0.0);
//gl.clear(gl.COLOR_BUFFER_BIT);
const shaderProgram = initShaderProgram(gl, VERTEX_SHADER, FRAGMENT_SHADER);
gl.useProgram(shaderProgram);
const positionLocation = gl.getAttribLocation(shaderProgram, 'position');
gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(positionLocation);
const in_resolution = gl.getUniformLocation(shaderProgram, 'in_resolution');
gl.uniform2fv(in_resolution, [canvas.width, canvas.height]);
const u_time = gl.getUniformLocation(shaderProgram, 'u_time');
const u_seed = gl.getUniformLocation(shaderProgram, 'u_seed');
const u_scale = gl.getUniformLocation(shaderProgram, 'u_scale');
const u_angle = gl.getUniformLocation(shaderProgram, 'u_angle');
const u_radius = gl.getUniformLocation(shaderProgram, 'u_radius');
const u_color = gl.getUniformLocation(shaderProgram, 'u_color');
gl.uniform1f(u_seed, Math.random() * 1000);
gl.uniform1f(u_scale, props.scale);
gl.uniform1f(u_angle, 0.0);
gl.uniform1f(u_radius, 0.15);
gl.uniform3fv(u_color, [0.5, 1.0, 0]);
if (isChromatic()) {
gl.uniform1f(u_time, 0);
gl.drawArrays(gl.TRIANGLES, 0, 6);
} else {
function render(timeStamp: number) {
let sizeChanged = false;
if (Math.abs(height - canvas.offsetHeight) > 2) {
height = canvas.offsetHeight;
canvas.height = height;
sizeChanged = true;
}
if (Math.abs(width - canvas.offsetWidth) > 2) {
width = canvas.offsetWidth;
canvas.width = width;
sizeChanged = true;
}
if (sizeChanged && gl) {
gl.uniform2fv(in_resolution, [width, height]);
gl.viewport(0, 0, width, height);
}
gl.uniform1f(u_time, timeStamp);
gl.drawArrays(gl.TRIANGLES, 0, 6);
handle = window.requestAnimationFrame(render);
}
handle = window.requestAnimationFrame(render);
}
});
onUnmounted(() => {
if (handle) {
window.cancelAnimationFrame(handle);
}
// TODO: WebGLãƒĒã‚Ŋãƒŧã‚šãŽč§Ŗæ”ž
});
</script>
<style lang="scss" module>
</style>

View File

@@ -68,7 +68,7 @@ receiveFollowRequest: "ØĒŲ„Ų‚ŲŠØĒ ØˇŲ„Ø¨ Ų…ØĒابؚ؊"
followRequestAccepted: "Ų‚ŲØ¨Ų„ ØˇŲ„Ø¨ Ø§Ų„Ų…ØĒابؚ؊"
mention: "ØŖØ´Øą Ø§Ų„Ų‰"
mentions: "Ø§Ų„ØĨØ´Ø§ØąØ§ØĒ"
directNotes: "ØąØŗØ§Ų„ØŠ ؎اØĩØŠ"
directNotes: "Ø§Ų„Ų…Ų„Ø§Ø­Ø¸Ø§ØĒ Ø§Ų„Ų…Ø¨Ø§Ø´ØąØŠ"
importAndExport: "ØĨØŗØĒŲˆØąØ¯ / ØĩØ¯Øą"
import: "Ø§ØŗØĒŲŠØąØ§Ø¯"
export: "ØĒØĩØ¯ŲŠØą"
@@ -215,6 +215,7 @@ noUsers: "Ų„ŲŠØŗ Ų‡Ų†Ø§Ųƒ Ų…ØŗØĒØŽØ¯Ų…ŲˆŲ†"
editProfile: "ØĒØšØ¯ŲŠŲ„ Ø§Ų„Ų…Ų„Ų Ø§Ų„ØĒØšØąŲŠŲŲŠ"
noteDeleteConfirm: "Ų‡Ų„ ØĒØąŲŠØ¯ Ø­Ø°Ų Ų‡Ø°Ų‡ Ø§Ų„Ų…Ų„Ø§Ø­Ø¸ØŠØŸ"
pinLimitExceeded: "Ų„Ø§ ŲŠŲ…ŲƒŲ†Ųƒ ØĒØĢØ¨ŲŠØĒ Ø§Ų„Ų…Ų„Ø§Ø­Ø¸Ø§ØĒ بؚد Ø§Ų„ØĸŲ†."
intro: "Ų„Ų‚Ø¯ Ø§Ų†ØĒŲ‡ØĒ ØšŲ…Ų„ŲŠØŠ ØĒŲ†ØĩŲŠØ¨ Misskey. Ø§Ų„ØąØŦØ§ØĄ ØĨŲ†Ø´Ø§ØĄ Ø­ØŗØ§Ø¨ ØĨØ¯Ø§ØąŲŠ."
done: "ØĒŲ…Ų‘"
processing: "Ø§Ų„Ų…ØšØ§Ų„ØŦØŠ ØŦØ§ØąŲŠØŠ"
preview: "Ų…ØšØ§ŲŠŲ†ØŠ"
@@ -250,6 +251,7 @@ removeAreYouSure: "Ų…ØĒØŖŲƒØ¯ Ų…Ų† ØŖŲ†Ųƒ ØĒØąŲŠØ¯ Ø­Ø°Ų {x}؟"
deleteAreYouSure: "Ų…ØĒØŖŲƒØ¯ Ų…Ų† ØŖŲ†Ųƒ ØĒØąŲŠØ¯ Ø­Ø°Ų {x}؟"
resetAreYouSure: "Ų‡Ų„ ØĒØąŲŠØ¯ ØĨؚاد؊ Ø§Ų„ØĒØšŲŠŲŠŲ†ØŸ"
saved: "Ø­ŲŲØ¸"
messaging: "Ø§Ų„Ų…Ø­Ø§Ø¯ØĢØŠ"
upload: "Ø§ØąŲØš"
keepOriginalUploading: "Ø§Ø¨Ų‚ Ø§Ų„ØĩŲˆØąØŠ Ø§Ų„ØŖØĩŲ„ŲŠØŠ"
keepOriginalUploadingDescription: "ŲŠØ­ŲØ¸ Ø§Ų„ØĩŲˆØą Ø§Ų„Ų…ØąŲŲˆØšØŠ ØšŲ„Ų‰ Ø­Ø§Ų„ØĒŲ‡Ø§ Ø§Ų„ØŖØĩŲ„ŲŠØŠØŒ ŲˆØ§Ų† ØšØˇŲ‘Ų„ ØŗØĒŲˆŲ„Ø¯ Ų†ØŗØŽØŠ Ų…ØŽØĩØĩØŠ Ų…Ų† Ø§Ų„ØĩŲˆØąØŠ."
@@ -262,6 +264,7 @@ uploadFromUrlMayTakeTime: "ØŗŲŠØŗØĒØēØąŲ‚ بؚØļ Ø§Ų„ŲˆŲ‚ØĒ Ų„Ø§ØĒŲ…Ø§Ų… Ø§Ų„Øą
explore: "Ø§ØŗØĒŲƒØ´Ø§Ų"
messageRead: "Ų…Ų‚ØąŲˆØĄØŠ"
noMoreHistory: "Ų„Ø§ ؊؈ØŦد Ø§Ų„Ų…Ø˛ŲŠØ¯ Ų…Ų† Ø§Ų„ØĒØ§ØąŲŠØŽ"
startMessaging: "Ø§Ø¨Ø¯ØŖ Ų…Ø­Ø§Ø¯ØĢØŠ"
nUsersRead: "Ų‚ØąØŖŲ‡ {n}"
agreeTo: "Ø§ŲˆØ§ŲŲ‚ ØšŲ„Ų‰ {0}"
agree: "ØŖŲ‚Ø¨Ų„"
@@ -433,6 +436,8 @@ retype: "ØŖØšØ¯ Ø§Ų„ŲƒØĒاب؊"
noteOf: "Ų…Ų„Ø§Ø­Ø¸Ø§ØĒ {user}"
quoteAttached: "Ø§ŲŲ‚ØĒŲØ¨ØŗŲŽ"
quoteQuestion: "ØŖØĒØąŲŠØ¯ ØĒØļŲ…ŲŠŲ†Ų‡Ø§ ŲƒØ§Ų‚ØĒØ¨Ø§Øŗ"
noMessagesYet: "Ų„ŲŠØŗ Ų‡Ų†Ø§Ųƒ ØąØŗØ§ØĻŲ„ بؚد"
newMessageExists: "Ų„Ų‚Ø¯ ØĒŲ„Ų‚ŲŠØĒ ØąØŗØ§Ų„ØŠ ØŦØ¯ŲŠØ¯ØŠ"
onlyOneFileCanBeAttached: "ŲŠŲ…ŲƒŲ†Ųƒ ØĨØąŲØ§Ų‚ ؅؄؁ ŲˆØ§Ø­Ø¯ Ø¨Ø§Ų„ØąØŗØ§Ų„ØŠ"
signinRequired: "ØąØŦØ§ØĄŲ‹ ؄ؐØŦ"
invitations: "Ø¯ØšŲˆØŠ"
@@ -675,6 +680,7 @@ experimental: "ا؎ØĒØ¨Ø§ØąŲŠ"
developer: "Ø§Ų„Ų…ØˇŲˆØą"
makeExplorable: "ØŖØ¸Ų‡Øą Ø§Ų„Ø­ØŗØ§Ø¨ ؁؊ ØĩŲØ­ØŠ \"Ø§ØŗØĒŲƒØ´Ø§Ų\""
makeExplorableDescription: "بØĒØšØˇŲŠŲ„ Ų‡Ø°Ø§ Ø§Ų„ØŽŲŠØ§Øą Ų„Ų† ŲŠØ¸Ų‡Øą Ø­ØŗØ§Ø¨Ųƒ ؁؊ ØĩŲØ­ØŠ \"Ø§ØŗØĒŲƒØ´Ø§Ų\""
showGapBetweenNotesInTimeline: "ØŖØ¸Ų‡Øą ؁ØŦŲˆØ§ØĒ Ø¨ŲŠŲ† Ø§Ų„Ų…Ø´Ø§ØąŲƒØ§ØĒ ؁؊ Ø§Ų„ØŽŲŠØˇ Ø§Ų„Ø˛Ų…Ų†ŲŠ"
left: "ŲŠØŗØ§Øą"
center: "ŲˆØŗØˇ"
wide: "ØšØąŲŠØļ"
@@ -1006,25 +1012,6 @@ sourceCode: "Ø§Ų„Ø´ŲØąØŠ Ø§Ų„Ų…ØĩØ¯ØąŲŠØŠ"
flip: "Ø§Ų‚Ų„Ø¨"
lastNDays: "ØĸØŽØą {n} ØŖŲŠØ§Ų…"
surrender: "ØŖŲ„Øēؐ"
postForm: "ØŖŲ†Ø´ØĻ Ų…Ų„Ø§Ø­Ø¸ØŠ"
information: "ØšŲ†"
inMinutes: "د"
inDays: "؊"
widgets: "Ø§Ų„ØĒØˇØ¨ŲŠŲ‚Ø§ØĒ Ø§Ų„Ų…ŲØĩØēŲ‘ØąØŠ"
presets: "ØĨؚداداØĒ Ų…ØŗØ¨Ų‚ØŠ"
_imageEditing:
_vars:
filename: "Ø§ØŗŲ… Ø§Ų„Ų…Ų„Ų"
_imageFrameEditor:
font: "Ø§Ų„ØŽØˇ"
fontSerif: "Serif"
fontSansSerif: "Sans Serif"
_chat:
invitations: "Ø¯ØšŲˆØŠ"
noHistory: "Ø§Ų„ØŗØŦŲ„ ŲØ§ØąØē"
members: "Ø§Ų„ØŖØšØļØ§ØĄ"
home: "Ø§Ų„ØąØĻŲŠØŗŲŠ"
send: "ØŖØąØŗŲ„"
_delivery:
stop: "Ų…ŲØšŲ„Ų‘Ų‚"
_initialAccountSetting:
@@ -1249,6 +1236,7 @@ _theme:
shadow: "Ø§Ų„Ø¸Ų„"
navBg: "ØŽŲ„ŲŲŠØŠ Ø§Ų„Ø´ØąŲŠØˇ Ø§Ų„ØŦØ§Ų†Ø¨ŲŠ"
navFg: "Ų†Øĩ Ø§Ų„Ø´ØąŲŠØˇ Ø§Ų„ØŦØ§Ų†Ø¨ŲŠ"
navHoverFg: "Ų†Øĩ Ø§Ų„Ø´ØąŲŠØˇ Ø§Ų„ØŦØ§Ų†Ø¨ŲŠ (ØšŲ†Ø¯ Ø§Ų„ØĒŲ…ØąŲŠØą ŲŲˆŲ‚Ų‡)"
link: "ØąØ§Ø¨Øˇ"
hashtag: "ŲˆØŗŲ…"
mention: "ØŖØ´Øą Ø§Ų„Ų‰"
@@ -1263,6 +1251,7 @@ _theme:
buttonBg: "ØŽŲ„ŲŲŠØŠ Ø§Ų„ØŖØ˛ØąØ§Øą"
buttonHoverBg: "ØŽŲ„ŲŲŠØŠ Ø§Ų„ØŖØ˛ØąØ§Øą (ØšŲ†Ø¯ Ø§Ų„ØĒŲ…ØąŲŠØą ŲŲˆŲ‚Ų‡Ø§)"
inputBorder: "Ø­ŲˆØ§Ų Ø­Ų‚Ų„ Ø§Ų„ØĨØ¯ØŽØ§Ų„"
driveFolderBg: "ØŽŲ„ŲŲŠØŠ Ų…ØŦŲ„Ø¯ Ų‚ØąØĩ Ø§Ų„ØĒØŽØ˛ŲŠŲ†"
messageBg: "ØŽŲ„ŲŲŠØŠ Ø§Ų„Ų…Ø­Ø§Ø¯ØĢØŠ"
_sfx:
note: "Ø§Ų„Ų…Ų„Ø§Ø­Ø¸Ø§ØĒ"
@@ -1322,7 +1311,6 @@ _permissions:
"read:gallery": "Ø§ØšØąØļ Ø§Ų„Ų…ØšØąØļ"
"write:gallery": "ØšØ¯Ų‘Ų„ Ø§Ų„Ų…ØšØąØļ"
"read:gallery-likes": "ŲŠØšØąØļ Ų…Ø§ ØŖØšØŦØ¨Ųƒ Ų…Ų† Ų…Ø´Ø§ØąŲƒØ§ØĒ Ø§Ų„Ų…ØšØąØļ"
"write:chat": "Ø§ŲƒØĒب ØŖŲˆ Ø§Ø­Ø°Ų ØąØŗØ§ØĻŲ„ Ų…Ø­Ø§Ø¯ØĢØŠ"
_auth:
shareAccess: "ØŖØĒØąŲŠØ¯ Ø§Ų„ØĒ؁؈؊Øļ Ų„Ų€ \"{name}\" Ø¨Ø§Ų„ŲˆØĩŲˆŲ„ Ų„Ø­ØŗØ§Ø¨ŲƒØŸ"
shareAccessAsk: "Ų‡Ų„ ØĒØŽŲˆŲ„ Ų„Ų‡Ø°Ø§ Ø§Ų„ØĒØˇØ¨ŲŠŲ‚ Ø§Ų„ŲˆØĩŲˆŲ„ Ų„Ø­ØŗØ§Ø¨ŲƒØŸ"
@@ -1365,14 +1353,6 @@ _widgets:
userList: "Ų‚Ø§ØĻŲ…ØŠ Ø§Ų„Ų…ØŗØĒØŽØ¯Ų…ŲŠŲ†"
_userList:
chooseList: "ا؎ØĒØą Ų‚Ø§ØĻŲ…ØŠ"
_widgetOptions:
height: "Ø§Ų„ØĨØąØĒŲØ§Øš"
_button:
colored: "Ų…Ų„ŲˆŲ‘Ų†"
_clock:
size: "Ø§Ų„Ø­ØŦŲ…"
_birthdayFollowings:
period: "Ø§Ų„Ų…Ø¯ØŠ"
_cw:
hide: "ØĨØŽŲØ§ØĄ"
show: "ØšØąØļ Ø§Ų„Ų…Ø˛ŲŠØ¯"
@@ -1413,9 +1393,6 @@ _postForm:
replyPlaceholder: "ØąØ¯ ØšŲ„Ų‰ Ų‡Ø°Ų‡ Ø§Ų„Ų…Ų„Ø§Ø­Ø¸ØŠâ€Ļ"
quotePlaceholder: "Ø§Ų‚ØĒØ¨Øŗ Ų‡Ø°Ų‡ Ø§Ų„Ų…Ų„Ø§Ø­Ø¸ØŠâ€Ļ"
channelPlaceholder: "Ø§Ų†Ø´Øą ؁؊ Ų‚Ų†Ø§ØŠ..."
_howToUse:
visibility_title: "Ø§Ų„Ø¸Ų‡ŲˆØą"
menu_title: "Ø§Ų„Ų‚Ø§ØĻŲ…ØŠ"
_placeholders:
a: "Ų…Ø§ Ø§Ų„Ø°ŲŠ ØĒŲ†ŲˆŲŠ ŲØšŲ„Ų‡ØŸ"
b: "Ų…Ø§Ø°Ø§ ŲŠØ­Ø¯ØĢ Ø­ŲˆŲ„Ųƒ ؟"
@@ -1611,21 +1588,3 @@ _search:
searchScopeAll: "Ø§Ų„ŲƒŲ„"
searchScopeLocal: "Ø§Ų„Ų…Ø­Ų„ŲŠ"
searchScopeUser: "Ų…ØŗØĒØŽØ¯Ų… Ų…Ø­Ø¯Ø¯"
_watermarkEditor:
opacity: "Ø§Ų„Ø´ŲØ§ŲŲŠØŠ"
scale: "Ø§Ų„Ø­ØŦŲ…"
text: "Ų†Øĩ"
position: "Ø§Ų„Ų…ŲˆØļØš"
type: "Ų†ŲˆØš"
image: "ØĩŲˆØą"
advanced: "Ų…ØĒŲ‚Ø¯Ų…"
_imageEffector:
_fxProps:
scale: "Ø§Ų„Ø­ØŦŲ…"
size: "Ø§Ų„Ø­ØŦŲ…"
offset: "Ø§Ų„Ų…ŲˆØļØš"
color: "Ø§Ų„Ų„ŲˆŲ†"
opacity: "Ø§Ų„Ø´ŲØ§ŲŲŠØŠ"
_qr:
showTabTitle: "Ø§Ų„Ų…Ø¸Ų‡Øą"
raw: "Ų†Øĩ"

View File

@@ -215,6 +215,7 @@ noUsers: "āϕ⧋āύ āĻŦā§āϝāĻžāĻŦāĻšāĻžāϰāĻ•āĻžāϰ⧀ āύ⧇āχ"
editProfile: "āĻĒā§āϰ⧋āĻĢāĻžāχāϞ āϏāĻŽā§āĻĒāĻžāĻĻāύāĻž āĻ•āϰ⧁āύ"
noteDeleteConfirm: "āφāĻĒāύāĻŋ āĻ•āĻŋ āύ⧋āϟ āĻĄāĻŋāϞāĻŋāϟ āĻ•āϰāĻžāϰ āĻŦā§āϝāĻžāĻĒāĻžāϰ⧇ āύāĻŋāĻļā§āϚāĻŋāϤ?"
pinLimitExceeded: "āφāĻĒāύāĻŋ āφāϰ āϕ⧋āύ āύ⧋āϟ āĻĒāĻŋāύ āĻ•āϰāϤ⧇ āĻĒāĻžāϰāĻŦ⧇āύ āύāĻž"
intro: "Misskey āĻāϰ āχāĻ¨ā§āϏāϟāϞ⧇āĻļāύ āϏāĻŽā§āĻĒāĻ¨ā§āύ āĻšā§Ÿā§‡āϛ⧇īŧāĻĻ⧟āĻž āĻ•āϰ⧇ āĻ…ā§āϝāĻžāĻĄāĻŽāĻŋāύ āχāωāϜāĻžāϰ āϤ⧈āϰāĻŋ āĻ•āϰ⧁āύāĨ¤"
done: "āϏāĻŽā§āĻĒāĻ¨ā§āύ"
processing: "āĻĒā§āϰāĻ•ā§āϰāĻŋ⧟āĻžāϧ⧀āύ..."
preview: "āĻĒā§‚āĻ°ā§āĻŦāϰ⧂āĻĒ āĻĻ⧇āϖ⧁āύ"
@@ -251,6 +252,7 @@ removeAreYouSure: "āφāĻĒāύāĻŋ āĻ•āĻŋ \"{x}\" āϏāϰāĻžāύ⧋āϰ āĻŦā§āϝāĻž
deleteAreYouSure: "āφāĻĒāύāĻŋ āĻ•āĻŋ \"{x}\" āϏāϰāĻžāύ⧋āϰ āĻŦā§āϝāĻžāĻĒāĻžāϰ⧇ āύāĻŋāĻļā§āϚāĻŋāϤ?"
resetAreYouSure: "āϰāĻŋāϏ⧇āϟ āĻ•āϰāĻžāϰ āĻŦā§āϝāĻžāĻĒāĻžāϰ⧇ āύāĻŋāĻļā§āϚāĻŋāϤ?"
saved: "āϏāĻ‚āϰāĻ•ā§āώāĻŋāϤ āĻšā§Ÿā§‡āϛ⧇"
messaging: "āĻšā§āϝāĻžāϟ"
upload: "āφāĻĒāϞ⧋āĻĄ"
keepOriginalUploading: "āφāϏāϞ āĻ›āĻŦāĻŋ āϰāĻžāϖ⧁āύ"
keepOriginalUploadingDescription: "āĻ›āĻŦāĻŋāϟāĻŋ āφāĻĒāϞ⧋āĻĄ āĻ•āϰāĻžāϰ āϏāĻŽāϝāĻŧ āφāϏāϞ āϏāĻ‚āĻ¸ā§āĻ•āϰāĻŖāϟāĻŋ āϰāĻžāϖ⧁āύāĨ¤ āĻ…āĻĒāĻļāύāϟāĻŋ āĻŦāĻ¨ā§āϧ āĻĨāĻžāĻ•āϞ⧇, āφāĻĒāϞ⧋āĻĄā§‡āϰ āϏāĻŽāϝāĻŧ āĻ“āϝāĻŧ⧇āĻŦ āĻĒā§āϰāĻ•āĻžāĻļāύāĻžāϰ āϜāĻ¨ā§āϝ āĻ›āĻŦāĻŋ āĻŦā§āϰāĻžāωāϜāĻžāϰ⧇ āϤ⧈āϰāĻŋ āĻ•āϰāĻž āĻšāĻŦ⧇āĨ¤"
@@ -263,6 +265,7 @@ uploadFromUrlMayTakeTime: "URL āĻšāϤ⧇ āφāĻĒāϞ⧋āĻĄ āĻšāϤ⧇ āĻ•āĻŋāϛ⧁
explore: "āϘ⧁āϰ⧇ āĻĻ⧇āϖ⧁āύ"
messageRead: "āĻĒāĻĄāĻŧāĻž"
noMoreHistory: "āφāϰ āϕ⧋āύ āχāϤāĻŋāĻšāĻžāϏ āύ⧇āχ"
startMessaging: "āĻšā§āϝāĻžāϟ āĻļ⧁āϰ⧁ āĻ•āϰ⧁āύ"
nUsersRead: "{n} āϜāύ āĻĒā§œā§‡āϛ⧇āύ"
agreeTo: "{0} āĻāϰ āĻĒā§āϰāϤāĻŋ āφāĻŽāĻŋ āϏāĻŽā§āĻŽāϤ"
start: "āĻļ⧁āϰ⧁ āĻ•āϰ⧁āύ"
@@ -424,6 +427,8 @@ retype: "āĻĒ⧁āύāσ āĻĒā§āϰāĻŦ⧇āĻļ"
noteOf: "{user} āĻāϰ āύ⧋āϟ"
quoteAttached: "āωāĻĻā§āϧ⧃āϤ"
quoteQuestion: "āωāĻĻā§āϧ⧃āϤāĻŋ āĻšāĻŋāϏāĻžāĻŦ⧇ āϏāĻ‚āϝ⧁āĻ•ā§āϤ āĻ•āϰāĻŦ⧇āύ?"
noMessagesYet: "āϕ⧋āύ āĻŽā§‡āϏ⧇āϜ āύ⧇āχ"
newMessageExists: "āύāϤ⧁āύ āĻŽā§‡āϏ⧇āϜ āĻĒā§‡ā§Ÿā§‡āϛ⧇āύ"
onlyOneFileCanBeAttached: "āφāĻĒāύāĻŋ āĻŽā§‡āϏ⧇āĻœā§‡āϰ āϏāĻžāĻĨ⧇ āϏāĻ°ā§āĻŦā§‹āĻšā§āϚ āĻāĻ•āϟāĻŋ āĻĢāĻžāχāϞ āϝ⧁āĻ•ā§āϤ āĻ•āϰāϤ⧇ āĻĒāĻžāϰāĻŦ⧇āύ"
signinRequired: "āĻĻāϝāĻŧāĻž āĻ•āϰ⧇ āϞāĻ— āχāύ āĻ•āϰ⧁āύ"
invitations: "āφāĻŽāĻ¨ā§āĻ¤ā§āϰāĻŖ"
@@ -672,6 +677,7 @@ experimentalFeatures: "āĻĒāϰ⧀āĻ•ā§āώāĻžāĻŽā§‚āϞāĻ• āĻŦ⧈āĻļāĻŋāĻˇā§āϟ
developer: "āĻĄā§‡āϭ⧇āϞāĻĒāĻžāϰ"
makeExplorable: "āĻ…ā§āϝāĻžāĻ•āĻžāωāĻ¨ā§āϟ \"āϘ⧁āϰ⧇ āĻĻ⧇āϖ⧁āύ\" āĻĒ⧃āĻˇā§āĻ āĻžā§Ÿ āĻĻ⧇āĻ–āĻžāύ"
makeExplorableDescription: "āφāĻĒāύāĻŋ āĻāϟāĻŋ āĻŦāĻ¨ā§āϧ āĻ•āϰāϞ⧇, āφāĻĒāύāĻžāϰ āĻ…ā§āϝāĻžāĻ•āĻžāωāĻ¨ā§āϟ \"āϘ⧁āϰ⧇ āĻĻ⧇āϖ⧁āύ\" āĻĒ⧃āĻˇā§āĻ āĻžā§Ÿ āĻĒā§āϰāĻĻāĻ°ā§āĻļāĻŋāϤ āĻšāĻŦ⧇ āύāĻžāĨ¤"
showGapBetweenNotesInTimeline: "āϟāĻžāχāĻŽāϞāĻžāχāύ āĻāĻŦāĻ‚ āύ⧋āĻŸā§‡āϰ āĻŽāĻžāĻā§‡ āĻĢāĻžāĻ•āĻž āϜāĻžā§ŸāĻ—āĻž āϰāĻžāϖ⧁āύ"
duplicate: "āĻĒā§āϰāϤāĻŋāϰ⧂āĻĒ"
left: "āĻŦāĻžāĻŽ"
center: "āĻŽāĻžāĻāĻ–āĻžāύ"
@@ -846,25 +852,6 @@ replies: "āϜāĻŦāĻžāĻŦ"
renotes: "āϰāĻŋāύ⧋āϟ"
sourceCode: "āϏ⧋āĻ°ā§āϏ āϕ⧋āĻĄ"
flip: "āωāĻ˛ā§āϟāĻžāύ"
postForm: "āύ⧋āϟ āϞāĻŋāϖ⧁āύ"
information: "āφāĻĒāύāĻžāϰ āϏāĻŽā§āĻĒāĻ°ā§āϕ⧇"
inMinutes: "āĻŽāĻŋāύāĻŋāϟ"
inDays: "āĻĻāĻŋāύ"
widgets: "āωāχāĻœā§‡āϟāϗ⧁āϞāĻŋ"
_imageEditing:
_vars:
filename: "āĻĢāĻžāχāϞ⧇āϰ āύāĻžāĻŽ"
_imageFrameEditor:
header: "āĻšā§‡āĻĄāĻžāϰ"
font: "āĻĢāĻ¨ā§āϟ"
fontSerif: "āϏ⧇āϰāĻŋāĻĢ"
fontSansSerif: "āĻ¸ā§āϝāĻžāĻ¨ā§āϏ āϏ⧇āϰāĻŋāĻĢ"
_chat:
invitations: "āφāĻŽāĻ¨ā§āĻ¤ā§āϰāĻŖ"
noHistory: "āϕ⧋āύ⧋ āχāϤāĻŋāĻšāĻžāϏ āύ⧇āχ"
members: "āϏāĻĻāĻ¸ā§āϝāĻŦ⧃āĻ¨ā§āĻĻ"
home: "āĻŽā§‚āϞ āĻĒāĻžāϤāĻž"
send: "āĻĒāĻžāĻ āĻžāύ"
_delivery:
stop: "āĻ¸ā§āĻĨāĻ—āĻŋāϤ āĻ•āϰāĻž āĻšā§Ÿā§‡āϛ⧇"
_type:
@@ -1007,6 +994,7 @@ _theme:
header: "āĻšā§‡āĻĄāĻžāϰ"
navBg: "āϏāĻžāχāĻĄāĻŦāĻžāϰ⧇āϰ āĻĒāϟāĻ­ā§‚āĻŽāĻŋ"
navFg: "āϏāĻžāχāĻĄāĻŦāĻžāϰ⧇āϰ āĻĒāĻžāĻ ā§āϝ"
navHoverFg: "āϏāĻžāχāĻĄāĻŦāĻžāϰ⧇āϰ āĻĒāĻžāĻ ā§āϝ (āĻšāĻ­āĻžāϰ)"
navActive: "āϏāĻžāχāĻĄāĻŦāĻžāϰ⧇āϰ āĻĒāĻžāĻ ā§āϝ (āĻ…ā§āϝāĻžāĻ•āϟāĻŋāĻ­)"
navIndicator: "āϏāĻžāχāĻĄāĻŦāĻžāϰ⧇āϰ āχāύāĻĄāĻŋāϕ⧇āϟāϰ"
link: "āϞāĻŋāĻ‚āĻ•"
@@ -1028,8 +1016,12 @@ _theme:
buttonBg: "āĻŦāĻžāϟāύ⧇āϰ āĻĒāϟāĻ­ā§‚āĻŽāĻŋ"
buttonHoverBg: "āĻŦāĻžāϟāύ⧇āϰ āĻĒāϟāĻ­ā§‚āĻŽāĻŋ (āĻšāĻ­āĻžāϰ)"
inputBorder: "āχāύāĻĒ⧁āϟ āĻĢāĻŋāĻ˛ā§āĻĄā§‡āϰ āĻŦāĻ°ā§āĻĄāĻžāϰ"
driveFolderBg: "āĻĄā§āϰāĻžāχāĻ­ āĻĢā§‹āĻ˛ā§āĻĄāĻžāϰ⧇āϰ āĻĒāϟāĻ­ā§‚āĻŽāĻŋ"
wallpaperOverlay: "āĻ“āϝāĻŧāĻžāϞāĻĒ⧇āĻĒāĻžāϰ āĻ“āĻ­āĻžāϰāϞ⧇"
badge: "āĻŦā§āϝāĻžāϜ"
messageBg: "āĻšā§āϝāĻžāĻŸā§‡āϰ āĻĒāϟāĻ­ā§‚āĻŽāĻŋ"
accentDarken: "āĻ…ā§āϝāĻžāĻ•āϏ⧇āĻ¨ā§āϟ (āĻ—āĻžā§)"
accentLighten: "āĻ…ā§āϝāĻžāĻ•āϏ⧇āĻ¨ā§āϟ (āĻšāĻžāĻ˛ā§āĻ•āĻž)"
fgHighlighted: "āĻšāĻžāχāϞāĻžāχāϟ āĻ•āϰāĻž āĻĒāĻžāĻ ā§āϝ"
_sfx:
note: "āύ⧋āϟāϗ⧁āϞāĻŋ"
@@ -1092,7 +1084,6 @@ _permissions:
"write:gallery": "āĻ—ā§āϝāĻžāϞāĻžāϰ⧀ āϏāĻŽā§āĻĒāĻžāĻĻāύāĻž āĻ•āϰ⧁āύ"
"read:gallery-likes": "āĻ—ā§āϝāĻžāϞāĻžāϰ⧀āϰ āĻĒāĻ›āĻ¨ā§āĻĻāϗ⧁āϞāĻŋ āĻĻ⧇āϖ⧁āύ"
"write:gallery-likes": "āĻ—ā§āϝāĻžāϞāĻžāϰ⧀āϰ āĻĒāĻ›āĻ¨ā§āĻĻāϗ⧁āϞāĻŋ āϏāĻŽā§āĻĒāĻžāĻĻāύāĻž āĻ•āϰ⧁āύ"
"write:chat": "āĻšā§āϝāĻžāϟāϗ⧁āϞāĻŋ āϏāĻŽā§āĻĒāĻžāĻĻāύāĻž āĻ•āϰ⧁āύ"
_auth:
shareAccess: "\"{name}\" āϕ⧇ āĻ…ā§āϝāĻžāĻ•āĻžāωāĻ¨ā§āĻŸā§‡āϰ āĻ…ā§āϝāĻžāĻ•ā§āϏ⧇āϏ āĻĻāĻŋāĻŦ⧇āύ?"
shareAccessAsk: "āĻ…ā§āϝāĻžāĻĒā§āϞāĻŋāϕ⧇āĻļāύāϟāĻŋāϕ⧇ āĻ…ā§āϝāĻžāĻ•āĻžāωāĻ¨ā§āĻŸā§‡āϰ āĻ…ā§āϝāĻžāĻ•ā§āϏ⧇āϏ āĻĻāĻŋāĻŦ⧇āύ?"
@@ -1137,14 +1128,6 @@ _widgets:
aichan: "āφāχ āϚāĻžāύ"
_userList:
chooseList: "āϞāĻŋāĻ¸ā§āϟ āύāĻŋāĻ°ā§āĻŦāĻžāϚāύ āĻ•āϰ⧁āύ"
_widgetOptions:
height: "āωāĻšā§āϚāϤāĻž"
_button:
colored: "āϰāĻ™ā§āĻ—āĻŋāύ"
_clock:
size: "āφāĻ•āĻžāϰ"
_birthdayFollowings:
period: "āĻŦā§āϝāĻžāĻĒā§āϤāĻŋāĻ•āĻžāϞ"
_cw:
hide: "āϞ⧁āĻ•āĻžāύ"
show: "āφāϰāĻ“ āĻĻ⧇āϖ⧁āύ"
@@ -1185,9 +1168,6 @@ _postForm:
replyPlaceholder: "āύ⧋āϟāϟāĻŋāϰ āϜāĻŦāĻžāĻŦ āĻĻāĻŋāύ..."
quotePlaceholder: "āύ⧋āϟāϟāĻŋāϕ⧇ āωāĻĻā§āϧ⧃āϤ āĻ•āϰ⧁āύ..."
channelPlaceholder: "āĻšā§āϝāĻžāύ⧇āϞ⧇ āĻĒā§‹āĻ¸ā§āϟ āĻ•āϰ⧁āύ..."
_howToUse:
visibility_title: "āĻĻ⧃āĻļā§āϝāĻŽāĻžāύāϤāĻž"
menu_title: "āĻŽā§‡āύ⧁"
_placeholders:
a: "āφāĻĒāύāĻŋ āĻāĻ–āύ āĻ•āĻŋ āĻ•āϰāϛ⧇āύ?"
b: "āφāĻĒāύāĻžāϰ āφāĻļ⧇ āĻĒāĻžāĻļ⧇ āĻ•āĻŋ āĻšāĻšā§āϛ⧇?"
@@ -1371,19 +1351,3 @@ _remoteLookupErrors:
_search:
searchScopeAll: "āϏāĻŦāϗ⧁āϞ⧋"
searchScopeLocal: "āĻ¸ā§āĻĨāĻžāύ⧀āϝāĻŧ"
_watermarkEditor:
opacity: "āĻ…āĻ¸ā§āĻŦāĻšā§āĻ›āϤāĻž"
scale: "āφāĻ•āĻžāϰ"
text: "āϞ⧇āĻ–āĻž"
image: "āĻ›āĻŦāĻŋ"
advanced: "āωāĻ¨ā§āύāϤ"
_imageEffector:
_fxProps:
scale: "āφāĻ•āĻžāϰ"
size: "āφāĻ•āĻžāϰ"
color: "āϰāĻ‚"
opacity: "āĻ…āĻ¸ā§āĻŦāĻšā§āĻ›āϤāĻž"
lightness: "āωāĻœā§āĻœā§āĻŦāϞ āĻ•āϰ⧁āύ"
_qr:
showTabTitle: "āĻĒā§āϰāĻĻāĻ°ā§āĻļāύ"
raw: "āϞ⧇āĻ–āĻž"

Some files were not shown because too many files have changed in this diff Show More