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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions public/registry/index.json
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
{
"version": 1,
"updatedAt": "2026-10-12T11:24:10.290Z",
"updatedAt": "2026-10-13T12:49:30.377Z",
"plugins": {
"count": 41,
"updatedAt": "2026-10-12T11:24:10.290Z"
"updatedAt": "2026-10-13T12:49:30.377Z"
},
"themes": {
"count": 77,
"updatedAt": "2026-10-12T11:24:10.290Z"
"updatedAt": "2026-10-13T12:49:30.377Z"
},
"widgets": {
"count": 64,
"updatedAt": "2026-10-12T11:24:10.290Z"
"updatedAt": "2026-10-13T12:49:30.377Z"
},
"skills": {
"count": 43,
"updatedAt": "2026-10-12T11:24:10.290Z"
"updatedAt": "2026-10-13T12:49:30.377Z"
},
"queries": {
"count": 35,
"updatedAt": "2026-10-12T11:24:10.290Z"
"updatedAt": "2026-10-13T12:49:30.377Z"
}
}
14 changes: 7 additions & 7 deletions public/registry/plugins.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"version": 1,
"updatedAt": "2026-10-12T11:24:10.290Z",
"updatedAt": "2026-10-13T12:49:30.377Z",
"plugins": [
{
"id": "ai-actions",
Expand Down Expand Up @@ -717,6 +717,7 @@
],
"profile": "full",
"permissions": [
"account.read",
"drive.read",
"drive.write",
"notes.write"
Expand All @@ -738,7 +739,7 @@
{
"id": "thread-to-memo",
"name": "スレッドをメモに保存",
"version": "1.0.0",
"version": "1.1.0",
"author": "hitalin",
"description": "ノートメニューから、そのノートが属するリプライツリー全体 (根から全リプライ) を Markdown にまとめて NoteDeck のメモに保存。深さ・件数の上限で打ち切った場合は末尾に明記",
"category": "utility",
Expand All @@ -753,7 +754,7 @@
],
"sourceUrl": "https://store.notedeck.io/registry/plugins/thread-to-memo/plugin.is",
"apiUrl": "https://store.notedeck.io/registry/plugins/thread-to-memo/api.json",
"sha512": "39a9975582f676ea56ac7c4c36fa4c2c09e53ad377f77aa70604d7a8130a50291388e0b5429c652bdec41af01316bd7b8af01266e76e9cd48fc31e77aaf917f6",
"sha512": "87314a73087a6b690fbcdd59214b978a13369a15c27eb996d552e67343d3b85d9c3193df537a7a5c299f803a142aea2803ed2d37f43e264b777ea5dc65ab3d19",
"createdAt": "2026-10-12T17:16:47+09:00",
"updatedAt": "2026-10-12T17:16:47+09:00",
"authorUrl": "https://github.com/hitalin",
Expand All @@ -780,11 +781,10 @@
],
"ndCalls": [
"memos.create",
"notes.children"
],
"mkApi": [
"notes/show"
"notes.children",
"notes.show"
],
"mkApi": [],
"hooks": [
"note_action"
],
Expand Down
2 changes: 1 addition & 1 deletion public/registry/plugins/thread-to-memo/api.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"type":"plugin","data":"/// @ 1.2.1\n\n// スレッドをメモに保存 — リプライツリー全体を Markdown にして NoteDeck のメモへ\n//\n// ノートメニューから、そのノートが属する会話 (根のノートから全リプライ) を\n// 1 つの Markdown にまとめて memos.create で保存する。AI は使わない。\n//\n// 1. 根を探す: 押したノートの replyId を Mk:api(\"notes/show\") で遡る。\n// Nd:call(\"notes.show\") の戻りは projection ({ id, username, text, createdAt })\n// で replyId を含まないため、遡りだけは本家 API (公開 endpoint、権限不要) を使う\n// 2. 子を集める: Nd:call(\"notes.children\") で各ノートの直接リプライを再帰取得。\n// 深さ (maxDepth) と総件数 (maxNotes) の上限を超えた分は打ち切り、末尾に記す\n// 3. memos.create で保存。確認ダイアログは NoteDeck 側 (confirm: true) が出すので\n// 自前の Mk:confirm は挟まない。キャンセル時は error 値 (user_cancelled) が返る\n//\n// NoteDeck 専用。使う NoteDeck 権限 (meta.json に記載):\n// - notes.read … notes.children (リプライの取得)\n// - memos.write … memos.create (メモの保存)\n\n### {\n\tname: \"スレッドをメモに保存\"\n\tversion: \"1.0.0\"\n\tauthor: \"@hitalin\"\n\tdescription: \"ノートメニューから、そのノートが属するリプライツリー全体を Markdown にまとめて NoteDeck のメモに保存します (NoteDeck 専用)\"\n}\n\nlet title = \"スレッドをメモに保存\"\n\n// AiScript の step 上限 (プラグイン 100000) に収まるよう固定の上限を置く\nlet maxDepth = 8\nlet maxNotes = 200\nlet childLimit = 100\n\n// 1 つのノートを表示用の共通形 { id, acct, text, createdAt } にそろえる\n@fromProjection(n) {\n\tlet text = if (Obj:has(n, \"text\") && n.text != null) n.text else \"\"\n\t{ id: n.id, acct: `@{n.username}`, text: text, createdAt: n.createdAt }\n}\n\n@fromFullNote(n) {\n\tlet user = n.user\n\tlet username = if (user == null || user.username == null) \"?\" else user.username\n\tlet host = if (user == null) null else user.host\n\tlet acct = if (host == null) `@{username}` else `@{username}@{host}`\n\tvar text = if (n.text == null) \"\" else n.text\n\tif (n.cw != null) text = `[CW: {n.cw}] {text}`\n\t{ id: n.id, acct: acct, text: text, createdAt: n.createdAt }\n}\n\n@indent(depth) {\n\tvar s = \"\"\n\tfor (depth) {\n\t\ts = `{s} `\n\t}\n\ts\n}\n\n// 根を探す。到達できなかった祖先があれば truncated.ancestors を立てる\n@findRoot(note, state) {\n\tvar cur = note\n\tvar hops = 0\n\tloop {\n\t\tif (cur.replyId == null) break\n\t\tif (hops >= 30) {\n\t\t\tstate.ancestors = true\n\t\t\tbreak\n\t\t}\n\t\tlet parent = Mk:api(\"notes/show\", { noteId: cur.replyId })\n\t\tif (Core:type(parent) != \"obj\") {\n\t\t\tstate.ancestors = true\n\t\t\tbreak\n\t\t}\n\t\tcur = parent\n\t\thops += 1\n\t}\n\tcur\n}\n\n// entry (共通形) を lines に書き、子を再帰的に続ける\n@collect(entry, depth, lines, state, targetId) {\n\tstate.count = state.count + 1\n\tlet pad = indent(depth)\n\tlet mark = if (entry.id == targetId) \" ←\" else \"\"\n\tlines.push(`{pad}- **{entry.acct}** ({entry.createdAt}){mark}`)\n\teach (let line, entry.text.split(Str:lf)) {\n\t\tif (line.trim() != \"\") lines.push(`{pad} {line}`)\n\t}\n\tif (depth >= maxDepth) {\n\t\t// 子がいるかは見ずに打ち切る (問い合わせ回数を抑える)\n\t\tstate.depth = true\n\t\treturn null\n\t}\n\tlet children = Nd:call(\"notes.children\", { noteId: entry.id, limit: childLimit })\n\tif (Core:type(children) != \"arr\") {\n\t\tstate.fetch = true\n\t\treturn null\n\t}\n\tif (children.len >= childLimit) state.width = true\n\teach (let child, children) {\n\t\tif (state.count >= maxNotes) {\n\t\t\tstate.notes = true\n\t\t\tbreak\n\t\t}\n\t\tcollect(fromProjection(child), depth + 1, lines, state, targetId)\n\t}\n\tnull\n}\n\nPlugin:register_note_action(\"スレッドをメモに保存\", @(note) {\n\tif (!(exists NOTEDECK)) {\n\t\tMk:dialog(title, \"このプラグインは NoteDeck 専用です。Misskey Web では動作しません\", \"info\")\n\t\treturn null\n\t}\n\tMk:toast(\"スレッドを収集しています…\", \"info\")\n\n\tvar state = { count: 0, ancestors: false, depth: false, width: false, notes: false, fetch: false }\n\tlet root = findRoot(note, state)\n\n\tvar lines = []\n\tlines.push(`# スレッド: {fromFullNote(root).acct} のノートから`)\n\tlines.push(\"\")\n\tlines.push(`根ノート: {root.id}`)\n\tif (root.uri != null) lines.push(`URL: {root.uri}`)\n\tlines.push(`起点ノート (←): {note.id}`)\n\tlines.push(\"\")\n\tcollect(fromFullNote(root), 0, lines, state, note.id)\n\n\tvar notes = []\n\tif (state.ancestors) notes.push(\"さらに上の親ノートは取得できなかったため、途中のノートを根として扱いました\")\n\tif (state.depth) notes.push(`深さ {maxDepth} を超えるリプライは省略しました`)\n\tif (state.notes) notes.push(`{maxNotes} 件に達したため、以降のリプライは省略しました`)\n\tif (state.width) notes.push(`1 ノートあたり {childLimit} 件を超えるリプライは省略しました`)\n\tif (state.fetch) notes.push(\"一部のリプライは取得に失敗したため省略しました\")\n\tif (notes.len > 0) {\n\t\tlines.push(\"\")\n\t\tlines.push(\"---\")\n\t\teach (let n, notes) {\n\t\t\tlines.push(`- (打ち切り) {n}`)\n\t\t}\n\t}\n\n\tlet saved = Nd:call(\"memos.create\", {\n\t\ttext: lines.join(Str:lf)\n\t\ttags: [\"thread\"]\n\t})\n\t// 確認ダイアログでキャンセルされた\n\tif (Core:type(saved) == \"error\") return null\n\tMk:toast(`スレッド {state.count} 件をメモに保存しました`, \"success\")\n\tnull\n})\n"}
{"type":"plugin","data":"/// @ 1.2.1\n\n// スレッドをメモに保存 — リプライツリー全体を Markdown にして NoteDeck のメモへ\n//\n// ノートメニューから、そのノートが属する会話 (根のノートから全リプライ) を\n// 1 つの Markdown にまとめて memos.create で保存する。AI は使わない。\n//\n// 1. 根を探す: 押したノートの replyId を Nd:call(\"notes.show\") で遡る。\n// 戻りの projection は replyId を持つ (NoteDeck 1.85.0 以降。親が無ければキーごと無い)。\n// Nd:call は失敗時に throw するので、親が削除済みなどで取れないと途中で止まる\n// 2. 子を集める: Nd:call(\"notes.children\") で各ノートの直接リプライを再帰取得。\n// 深さ (maxDepth) と総件数 (maxNotes) の上限を超えた分は打ち切り、末尾に記す\n// 3. memos.create で保存。確認ダイアログは NoteDeck 側 (confirm: true) が出すので\n// 自前の Mk:confirm は挟まない。キャンセル時は error 値 (user_cancelled) が返る\n//\n// NoteDeck 専用。使う NoteDeck 権限 (meta.json に記載):\n// - notes.read … notes.show / notes.children (親とリプライの取得)\n// - memos.write … memos.create (メモの保存)\n\n### {\n\tname: \"スレッドをメモに保存\"\n\tversion: \"1.1.0\"\n\tauthor: \"@hitalin\"\n\tdescription: \"ノートメニューから、そのノートが属するリプライツリー全体を Markdown にまとめて NoteDeck のメモに保存します (NoteDeck 専用)\"\n}\n\nlet title = \"スレッドをメモに保存\"\n\n// AiScript の step 上限 (プラグイン 100000) に収まるよう固定の上限を置く\nlet maxDepth = 8\nlet maxNotes = 200\nlet childLimit = 100\n\n// 1 つのノートを表示用の共通形 { id, acct, text, createdAt } にそろえる\n// projection の username は host を含まない。text は CW なら \"[CW: …]\" に置き換わっている\n@fromProjection(n) {\n\tlet text = if (Obj:has(n, \"text\") && n.text != null) n.text else \"\"\n\tlet replyId = if (Obj:has(n, \"replyId\")) n.replyId else null\n\t{ id: n.id, acct: `@{n.username}`, text: text, createdAt: n.createdAt, replyId: replyId, uri: null }\n}\n\n@fromFullNote(n) {\n\tlet user = n.user\n\tlet username = if (user == null || user.username == null) \"?\" else user.username\n\tlet host = if (user == null) null else user.host\n\tlet acct = if (host == null) `@{username}` else `@{username}@{host}`\n\tvar text = if (n.text == null) \"\" else n.text\n\tif (n.cw != null) text = `[CW: {n.cw}] {text}`\n\t{ id: n.id, acct: acct, text: text, createdAt: n.createdAt, replyId: n.replyId, uri: n.uri }\n}\n\n@indent(depth) {\n\tvar s = \"\"\n\tfor (depth) {\n\t\ts = `{s} `\n\t}\n\ts\n}\n\n// 根を探して共通形で返す。遡りの上限に達したら state.ancestors を立てる\n@findRoot(note, state) {\n\tvar cur = fromFullNote(note)\n\tvar hops = 0\n\tloop {\n\t\tif (cur.replyId == null) break\n\t\tif (hops >= 30) {\n\t\t\tstate.ancestors = true\n\t\t\tbreak\n\t\t}\n\t\tlet parent = Nd:call(\"notes.show\", { noteId: cur.replyId })\n\t\tif (Core:type(parent) != \"obj\") {\n\t\t\tstate.ancestors = true\n\t\t\tbreak\n\t\t}\n\t\tcur = fromProjection(parent)\n\t\thops += 1\n\t}\n\tcur\n}\n\n// entry (共通形) を lines に書き、子を再帰的に続ける\n@collect(entry, depth, lines, state, targetId) {\n\tstate.count = state.count + 1\n\tlet pad = indent(depth)\n\tlet mark = if (entry.id == targetId) \" ←\" else \"\"\n\tlines.push(`{pad}- **{entry.acct}** ({entry.createdAt}){mark}`)\n\teach (let line, entry.text.split(Str:lf)) {\n\t\tif (line.trim() != \"\") lines.push(`{pad} {line}`)\n\t}\n\tif (depth >= maxDepth) {\n\t\t// 子がいるかは見ずに打ち切る (問い合わせ回数を抑える)\n\t\tstate.depth = true\n\t\treturn null\n\t}\n\tlet children = Nd:call(\"notes.children\", { noteId: entry.id, limit: childLimit })\n\tif (Core:type(children) != \"arr\") {\n\t\tstate.fetch = true\n\t\treturn null\n\t}\n\tif (children.len >= childLimit) state.width = true\n\teach (let child, children) {\n\t\tif (state.count >= maxNotes) {\n\t\t\tstate.notes = true\n\t\t\tbreak\n\t\t}\n\t\tcollect(fromProjection(child), depth + 1, lines, state, targetId)\n\t}\n\tnull\n}\n\nPlugin:register_note_action(\"スレッドをメモに保存\", @(note) {\n\tif (!(exists NOTEDECK)) {\n\t\tMk:dialog(title, \"このプラグインは NoteDeck 専用です。Misskey Web では動作しません\", \"info\")\n\t\treturn null\n\t}\n\tMk:toast(\"スレッドを収集しています…\", \"info\")\n\n\tvar state = { count: 0, ancestors: false, depth: false, width: false, notes: false, fetch: false }\n\tlet root = findRoot(note, state)\n\n\tvar lines = []\n\tlines.push(`# スレッド: {root.acct} のノートから`)\n\tlines.push(\"\")\n\tlines.push(`根ノート: {root.id}`)\n\t// uri は起点ノート (本家のノート全体) にしか無い。projection で遡った根では出さない\n\tif (root.uri != null) lines.push(`URL: {root.uri}`)\n\tlines.push(`起点ノート (←): {note.id}`)\n\tlines.push(\"\")\n\tcollect(root, 0, lines, state, note.id)\n\n\tvar notes = []\n\tif (state.ancestors) notes.push(\"さらに上の親ノートは取得できなかったため、途中のノートを根として扱いました\")\n\tif (state.depth) notes.push(`深さ {maxDepth} を超えるリプライは省略しました`)\n\tif (state.notes) notes.push(`{maxNotes} 件に達したため、以降のリプライは省略しました`)\n\tif (state.width) notes.push(`1 ノートあたり {childLimit} 件を超えるリプライは省略しました`)\n\tif (state.fetch) notes.push(\"一部のリプライは取得に失敗したため省略しました\")\n\tif (notes.len > 0) {\n\t\tlines.push(\"\")\n\t\tlines.push(\"---\")\n\t\teach (let n, notes) {\n\t\t\tlines.push(`- (打ち切り) {n}`)\n\t\t}\n\t}\n\n\tlet saved = Nd:call(\"memos.create\", {\n\t\ttext: lines.join(Str:lf)\n\t\ttags: [\"thread\"]\n\t})\n\t// 確認ダイアログでキャンセルされた\n\tif (Core:type(saved) == \"error\") return null\n\tMk:toast(`スレッド {state.count} 件をメモに保存しました`, \"success\")\n\tnull\n})\n"}
4 changes: 2 additions & 2 deletions public/registry/plugins/thread-to-memo/meta.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"id": "thread-to-memo",
"name": "スレッドをメモに保存",
"version": "1.0.0",
"version": "1.1.0",
"author": "hitalin",
"authorUrl": "https://github.com/hitalin",
"description": "ノートメニューから、そのノートが属するリプライツリー全体 (根から全リプライ) を Markdown にまとめて NoteDeck のメモに保存。深さ・件数の上限で打ち切った場合は末尾に明記",
Expand All @@ -10,5 +10,5 @@
"capabilities": ["notedeck-api"],
"tags": ["memo", "thread", "pkm", "note-action"],
"permissions": ["notes.read", "memos.write"],
"minNoteDeckVersion": "1.55.0"
"minNoteDeckVersion": "1.85.0"
}
29 changes: 16 additions & 13 deletions public/registry/plugins/thread-to-memo/plugin.is
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,21 @@
// ノートメニューから、そのノートが属する会話 (根のノートから全リプライ) を
// 1 つの Markdown にまとめて memos.create で保存する。AI は使わない。
//
// 1. 根を探す: 押したノートの replyId を Mk:api("notes/show") で遡る。
// Nd:call("notes.show") の戻りは projection ({ id, username, text, createdAt })
// で replyId を含まないため、遡りだけは本家 API (公開 endpoint、権限不要) を使う
// 1. 根を探す: 押したノートの replyId を Nd:call("notes.show") で遡る。
// 戻りの projection は replyId を持つ (NoteDeck 1.85.0 以降。親が無ければキーごと無い)。
// Nd:call は失敗時に throw するので、親が削除済みなどで取れないと途中で止まる
// 2. 子を集める: Nd:call("notes.children") で各ノートの直接リプライを再帰取得。
// 深さ (maxDepth) と総件数 (maxNotes) の上限を超えた分は打ち切り、末尾に記す
// 3. memos.create で保存。確認ダイアログは NoteDeck 側 (confirm: true) が出すので
// 自前の Mk:confirm は挟まない。キャンセル時は error 値 (user_cancelled) が返る
//
// NoteDeck 専用。使う NoteDeck 権限 (meta.json に記載):
// - notes.read … notes.children (リプライの取得)
// - notes.read … notes.show / notes.children (親とリプライの取得)
// - memos.write … memos.create (メモの保存)

### {
name: "スレッドをメモに保存"
version: "1.0.0"
version: "1.1.0"
author: "@hitalin"
description: "ノートメニューから、そのノートが属するリプライツリー全体を Markdown にまとめて NoteDeck のメモに保存します (NoteDeck 専用)"
}
Expand All @@ -32,9 +32,11 @@ let maxNotes = 200
let childLimit = 100

// 1 つのノートを表示用の共通形 { id, acct, text, createdAt } にそろえる
// projection の username は host を含まない。text は CW なら "[CW: …]" に置き換わっている
@fromProjection(n) {
let text = if (Obj:has(n, "text") && n.text != null) n.text else ""
{ id: n.id, acct: `@{n.username}`, text: text, createdAt: n.createdAt }
let replyId = if (Obj:has(n, "replyId")) n.replyId else null
{ id: n.id, acct: `@{n.username}`, text: text, createdAt: n.createdAt, replyId: replyId, uri: null }
}

@fromFullNote(n) {
Expand All @@ -44,7 +46,7 @@ let childLimit = 100
let acct = if (host == null) `@{username}` else `@{username}@{host}`
var text = if (n.text == null) "" else n.text
if (n.cw != null) text = `[CW: {n.cw}] {text}`
{ id: n.id, acct: acct, text: text, createdAt: n.createdAt }
{ id: n.id, acct: acct, text: text, createdAt: n.createdAt, replyId: n.replyId, uri: n.uri }
}

@indent(depth) {
Expand All @@ -55,22 +57,22 @@ let childLimit = 100
s
}

// 根を探す。到達できなかった祖先があれば truncated.ancestors を立てる
// 根を探して共通形で返す。遡りの上限に達したら state.ancestors を立てる
@findRoot(note, state) {
var cur = note
var cur = fromFullNote(note)
var hops = 0
loop {
if (cur.replyId == null) break
if (hops >= 30) {
state.ancestors = true
break
}
let parent = Mk:api("notes/show", { noteId: cur.replyId })
let parent = Nd:call("notes.show", { noteId: cur.replyId })
if (Core:type(parent) != "obj") {
state.ancestors = true
break
}
cur = parent
cur = fromProjection(parent)
hops += 1
}
cur
Expand Down Expand Up @@ -117,13 +119,14 @@ Plugin:register_note_action("スレッドをメモに保存", @(note) {
let root = findRoot(note, state)

var lines = []
lines.push(`# スレッド: {fromFullNote(root).acct} のノートから`)
lines.push(`# スレッド: {root.acct} のノートから`)
lines.push("")
lines.push(`根ノート: {root.id}`)
// uri は起点ノート (本家のノート全体) にしか無い。projection で遡った根では出さない
if (root.uri != null) lines.push(`URL: {root.uri}`)
lines.push(`起点ノート (←): {note.id}`)
lines.push("")
collect(fromFullNote(root), 0, lines, state, note.id)
collect(root, 0, lines, state, note.id)

var notes = []
if (state.ancestors) notes.push("さらに上の親ノートは取得できなかったため、途中のノートを根として扱いました")
Expand Down
2 changes: 1 addition & 1 deletion public/registry/queries.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"version": 1,
"updatedAt": "2026-10-12T11:24:10.290Z",
"updatedAt": "2026-10-13T12:49:30.377Z",
"queries": [
{
"id": "bot-only",
Expand Down
Loading
Loading