diff --git a/public/registry/index.json b/public/registry/index.json index 98a98ee..86f4a53 100644 --- a/public/registry/index.json +++ b/public/registry/index.json @@ -1,24 +1,24 @@ { "version": 1, - "updatedAt": "2026-08-09T10:23:15.471Z", + "updatedAt": "2026-08-11T04:14:55.998Z", "plugins": { "count": 24, - "updatedAt": "2026-08-09T10:23:15.471Z" + "updatedAt": "2026-08-11T04:14:55.998Z" }, "themes": { "count": 54, - "updatedAt": "2026-08-09T10:23:15.471Z" + "updatedAt": "2026-08-11T04:14:55.998Z" }, "widgets": { "count": 45, - "updatedAt": "2026-08-09T10:23:15.471Z" + "updatedAt": "2026-08-11T04:14:55.998Z" }, "skills": { "count": 29, - "updatedAt": "2026-08-09T10:23:15.471Z" + "updatedAt": "2026-08-11T04:14:55.998Z" }, "queries": { "count": 24, - "updatedAt": "2026-08-09T10:23:15.471Z" + "updatedAt": "2026-08-11T04:14:55.998Z" } } diff --git a/public/registry/plugins.json b/public/registry/plugins.json index dc80bd2..0af99d4 100644 --- a/public/registry/plugins.json +++ b/public/registry/plugins.json @@ -1,6 +1,6 @@ { "version": 1, - "updatedAt": "2026-08-07T01:20:05.144Z", + "updatedAt": "2026-08-11T04:14:55.998Z", "plugins": [ { "id": "plugin-smith", @@ -19,7 +19,7 @@ ], "sourceUrl": "https://store.notedeck.io/registry/plugins/plugin-smith/plugin.is", "apiUrl": "https://store.notedeck.io/registry/plugins/plugin-smith/api.json", - "sha512": "b3d84b8a725d291b00335daeceebdb52aef71b0c2739b45a540fa760af110a61de8b90db097fb863c638e8d82af429d4d3d75bc7920e5681e77d700cbfef84de", + "sha512": "e3c15224e18886a0021380b7f001d58383421958b1128384fc2d25749cb9e82bab527a7cf5042222051f6ee434111bdee8efe7b89f305d902cbe15b4592748ad", "createdAt": "2026-05-12T11:12:35+09:00", "updatedAt": "2026-07-20T23:42:10+09:00", "authorUrl": "https://github.com/hitalin", diff --git a/public/registry/plugins/plugin-smith/api.json b/public/registry/plugins/plugin-smith/api.json index ae97365..d917d25 100644 --- a/public/registry/plugins/plugin-smith/api.json +++ b/public/registry/plugins/plugin-smith/api.json @@ -1 +1 @@ -{"type":"plugin","data":"/// @ 1.2.1\n/// Plugin Smith — AiScript プラグインのソース生成\n///\n/// クリップボードに「こういうプラグインが欲しい」と書いて起動すると、\n/// 既存プラグインの作りを参考に AI が AiScript ソースを生成し、\n/// `plugins.create` の確認ダイアログにソース全文を表示する。\n///\n/// v0.1 は生成結果をクリップボードに書き戻していたが、それだと元の\n/// クリップボードを上書きしてしまい中身を確認しづらい。そこで NoteDeck の\n/// インストール確認ダイアログ (コードプレビュー付き) でレビューする方式にした。\n///\n/// 安全性:\n/// - plugins.create は必ず active:false (無効) で作られ、handler は走らない\n/// - インストール前に確認ダイアログでソース全文が見える\n/// - 有効化はプラグインカラムから手動 (= 二重承認境界)\n\n### {\n\tname: \"Plugin Smith\"\n\tversion: \"0.2.0\"\n\tauthor: \"@hitalin\"\n\tdescription: \"AI が AiScript プラグインを生成し、確認ダイアログでレビュー (有効化は手動)\"\n}\n\n// ─────────────────────────────\n// ヘルパー\n// ─────────────────────────────\n\n/// 生成テキストから 3 連バッククォートのコードフェンスを剥がす\n/// (AI が指示を無視してフェンスを付けてきた場合の保険)\n@stripFence(raw) {\n\tvar t = raw.trim()\n\tif (!t.starts_with(\"```\")) { return t }\n\tlet parts = t.split(\"```\")\n\t// parts[0] = \"\" / parts[1] = フェンス内本体 / parts[2] = 末尾\n\tif (parts.len < 2) { return t }\n\tvar inner = parts[1]\n\t// 先頭が言語タグ行 (aiscript / is 等) なら 1 行落とす\n\tlet nl = inner.index_of(Str:lf)\n\tif (nl >= 0) {\n\t\tlet first = inner.slice(0, nl).trim()\n\t\tif (first.len <= 12 && !first.incl(\" \")) {\n\t\t\tinner = inner.slice(nl + 1, inner.len)\n\t\t}\n\t}\n\tinner.trim()\n}\n\n@generate() {\n\tlet clip = Nd:call('clipboard.read', {})\n\tif (clip.text == \"\" || clip.text == null) {\n\t\tNd:call('ui.notify', {\n\t\t\ttitle: \"Plugin Smith\"\n\t\t\tbody: \"クリップボードに「こういうプラグインが欲しい」を書いてから起動してください\"\n\t\t})\n\t\treturn null\n\t}\n\n\t// 既存プラグインをフォーマットの参考に\n\tlet installed = Nd:call('plugins.list', {})\n\tvar sampleNames = []\n\teach (let p, installed) { sampleNames.push(p.name) }\n\tlet sampleHint = if (sampleNames.len > 0) {\n\t\t`参考にできる既存プラグイン: {sampleNames.join(\", \")}`\n\t} else {\n\t\t\"(まだ他のプラグインは入っていません)\"\n\t}\n\n\t// プロンプトは波括弧やバッククォートを含むため、テンプレートリテラルを使わず\n\t// \"...\" (補間なし) の行配列を join で組み立てる。\n\tlet rules = [\n\t\t\"あなたは NoteDeck の AiScript プラグイン作者です。ユーザーの要望から AiScript ソースを生成してください。\"\n\t\t\"\"\n\t\t\"【NoteDeck の規約】\"\n\t\t\"- 冒頭に ### { name, version, author, description } メタブロックを置く\"\n\t\t\"- コマンド登録は Nd:register_command(id, label, icon, handler, options)\"\n\t\t\"- AI 呼び出しは Nd:call('ai.chat', { prompt })\"\n\t\t\"- クリップボードは Nd:call('clipboard.read', {}) / Nd:call('clipboard.write', { text })\"\n\t\t\"- 通知は Nd:call('ui.notify', { title, body })\"\n\t\t\"- 文字列・配列はメソッド形式で操作する (s.split(',') / arr.push(v) / arr.len)。Str:split のような名前空間関数は無い\"\n\t\t\"\"\n\t\t\"【出力形式 — 厳守】\"\n\t\t\"- 1 行目に NAME: <プラグイン名> だけを書く\"\n\t\t\"- 2 行目以降は AiScript ソース本体のみ (### メタブロックから開始)\"\n\t\t\"- コードフェンスや説明文は一切付けない\"\n\t].join(Str:lf)\n\n\tlet prompt = [\n\t\trules\n\t\t\"\"\n\t\t\"【ユーザー要望】\"\n\t\tclip.text\n\t\t\"\"\n\t\t\"【参考】\"\n\t\tsampleHint\n\t].join(Str:lf)\n\n\tlet result = Nd:call('ai.chat', { prompt: prompt })\n\tlet cleaned = stripFence(result.response)\n\n\t// 1 行目の NAME: からプラグイン名を取り出し、本体と分離する\n\tlet lines = cleaned.split(Str:lf)\n\tvar name = \"生成プラグイン\"\n\tvar bodyStart = 0\n\tif (lines.len > 0 && lines[0].trim().starts_with(\"NAME:\")) {\n\t\tlet head = lines[0].trim()\n\t\tname = head.slice(5, head.len).trim()\n\t\tbodyStart = 1\n\t}\n\tif (name == \"\") { name = \"生成プラグイン\" }\n\tlet src = lines.slice(bodyStart, lines.len).join(Str:lf).trim()\n\n\t// 確認ダイアログに出せるのは構文の通るソースだけなので、先に検証する\n\tlet check = Nd:call('aiscript.validate', { src: src, entryPoint: \"plugin\" })\n\tif (!check.ok) {\n\t\t// 壊れたソースはダイアログに出せない。失われないようクリップボードへ退避し、\n\t\t// エラー内容を通知する (異常系でのみクリップボードを使う)。\n\t\tNd:call('clipboard.write', { text: src })\n\t\tvar diag = \"\"\n\t\teach (let d, check.diagnostics) {\n\t\t\tdiag = `{diag}L{d.line}:{d.column} {d.message}{Str:lf}`\n\t\t}\n\t\tNd:call('ui.notify', {\n\t\t\ttitle: \"Plugin Smith — 構文エラー\"\n\t\t\tbody: `生成結果に構文エラーがありました。修正用にクリップボードへ退避しました。{Str:lf}{Str:lf}{diag}`\n\t\t})\n\t\treturn null\n\t}\n\n\t// 確認ダイアログにソース全文 (is ハイライト) が表示される。\n\t// active:false で作成され handler は走らない。有効化はユーザーが手動で。\n\tNd:call('plugins.create', {\n\t\tname: name\n\t\tsrc: src\n\t\tauthor: \"@plugin-smith\"\n\t\tdescription: \"Plugin Smith が生成 (有効化前に内容を確認してください)\"\n\t})\n}\n\nNd:register_command(\n\t'plugin-smith:run'\n\t'Plugin Smith — AiScript 生成'\n\t'ti-tools'\n\t@() { generate() }\n\t{ permissions: ['ai.invoke', 'clipboard', 'plugins.read', 'plugins.write', 'notifications'] }\n)\n"} +{"type":"plugin","data":"/// @ 1.2.1\n/// Plugin Smith — AiScript プラグインのソース生成\n///\n/// クリップボードに「こういうプラグインが欲しい」と書いて起動すると、\n/// 既存プラグインの作りを参考に AI が AiScript ソースを生成し、\n/// `plugins.create` の確認ダイアログにソース全文を表示する。\n///\n/// v0.1 は生成結果をクリップボードに書き戻していたが、それだと元の\n/// クリップボードを上書きしてしまい中身を確認しづらい。そこで NoteDeck の\n/// インストール確認ダイアログ (コードプレビュー付き) でレビューする方式にした。\n///\n/// 安全性:\n/// - plugins.create は必ず active:false (無効) で作られ、handler は走らない\n/// - インストール前に確認ダイアログでソース全文が見える\n/// - 有効化はプラグインカラムから手動 (= 二重承認境界)\n\n### {\n\tname: \"Plugin Smith\"\n\tversion: \"0.2.0\"\n\tauthor: \"@hitalin\"\n\tdescription: \"AI が AiScript プラグインを生成し、確認ダイアログでレビュー (有効化は手動)\"\n}\n\n// ─────────────────────────────\n// ヘルパー\n// ─────────────────────────────\n\n/// 生成テキストから 3 連バッククォートのコードフェンスを剥がす\n/// (AI が指示を無視してフェンスを付けてきた場合の保険)\n@stripFence(raw) {\n\tvar t = raw.trim()\n\tif (!t.starts_with(\"```\")) { return t }\n\tlet parts = t.split(\"```\")\n\t// parts[0] = \"\" / parts[1] = フェンス内本体 / parts[2] = 末尾\n\tif (parts.len < 2) { return t }\n\tvar inner = parts[1]\n\t// 先頭が言語タグ行 (aiscript / is 等) なら 1 行落とす\n\tlet nl = inner.index_of(Str:lf)\n\tif (nl >= 0) {\n\t\tlet first = inner.slice(0, nl).trim()\n\t\tif (first.len <= 12 && !first.incl(\" \")) {\n\t\t\tinner = inner.slice(nl + 1, inner.len)\n\t\t}\n\t}\n\tinner.trim()\n}\n\n@generate() {\n\tlet clip = Nd:call('clipboard.read', {})\n\tif (clip.text == \"\" || clip.text == null) {\n\t\tNd:call('ui.notify', {\n\t\t\ttitle: \"Plugin Smith\"\n\t\t\tbody: \"クリップボードに「こういうプラグインが欲しい」を書いてから起動してください\"\n\t\t})\n\t\treturn null\n\t}\n\n\t// 既存プラグインをフォーマットの参考に\n\tlet installed = Nd:call('plugins.list', {})\n\tvar sampleNames = []\n\teach (let p, installed) { sampleNames.push(p.name) }\n\tlet sampleHint = if (sampleNames.len > 0) {\n\t\t`参考にできる既存プラグイン: {sampleNames.join(\", \")}`\n\t} else {\n\t\t\"(まだ他のプラグインは入っていません)\"\n\t}\n\n\t// プロンプトは波括弧やバッククォートを含むため、テンプレートリテラルを使わず\n\t// \"...\" (補間なし) の行配列を join で組み立てる。\n\tlet rules = [\n\t\t\"あなたは NoteDeck の AiScript プラグイン作者です。ユーザーの要望から AiScript ソースを生成してください。\"\n\t\t\"\"\n\t\t\"【NoteDeck の規約】\"\n\t\t\"- 冒頭に ### { name, version, author, description } メタブロックを置く\"\n\t\t\"- コマンド登録は Nd:register_command(id, label, icon, handler, options)。id に : は使えない (英数字とハイフンのみ)\"\n\t\t\"- AI 呼び出しは Nd:call('ai.chat', { prompt })\"\n\t\t\"- クリップボードは Nd:call('clipboard.read', {}) / Nd:call('clipboard.write', { text })\"\n\t\t\"- 通知は Nd:call('ui.notify', { title, body })\"\n\t\t\"- 文字列・配列はメソッド形式で操作する (s.split(',') / arr.push(v) / arr.len)。Str:split のような名前空間関数は無い\"\n\t\t\"\"\n\t\t\"【出力形式 — 厳守】\"\n\t\t\"- 1 行目に NAME: <プラグイン名> だけを書く\"\n\t\t\"- 2 行目以降は AiScript ソース本体のみ (### メタブロックから開始)\"\n\t\t\"- コードフェンスや説明文は一切付けない\"\n\t].join(Str:lf)\n\n\tlet prompt = [\n\t\trules\n\t\t\"\"\n\t\t\"【ユーザー要望】\"\n\t\tclip.text\n\t\t\"\"\n\t\t\"【参考】\"\n\t\tsampleHint\n\t].join(Str:lf)\n\n\tlet result = Nd:call('ai.chat', { prompt: prompt })\n\tlet cleaned = stripFence(result.response)\n\n\t// 1 行目の NAME: からプラグイン名を取り出し、本体と分離する\n\tlet lines = cleaned.split(Str:lf)\n\tvar name = \"生成プラグイン\"\n\tvar bodyStart = 0\n\tif (lines.len > 0 && lines[0].trim().starts_with(\"NAME:\")) {\n\t\tlet head = lines[0].trim()\n\t\tname = head.slice(5, head.len).trim()\n\t\tbodyStart = 1\n\t}\n\tif (name == \"\") { name = \"生成プラグイン\" }\n\tlet src = lines.slice(bodyStart, lines.len).join(Str:lf).trim()\n\n\t// 確認ダイアログに出せるのは構文の通るソースだけなので、先に検証する\n\tlet check = Nd:call('aiscript.validate', { src: src, entryPoint: \"plugin\" })\n\tif (!check.ok) {\n\t\t// 壊れたソースはダイアログに出せない。失われないようクリップボードへ退避し、\n\t\t// エラー内容を通知する (異常系でのみクリップボードを使う)。\n\t\tNd:call('clipboard.write', { text: src })\n\t\tvar diag = \"\"\n\t\teach (let d, check.diagnostics) {\n\t\t\tdiag = `{diag}L{d.line}:{d.column} {d.message}{Str:lf}`\n\t\t}\n\t\tNd:call('ui.notify', {\n\t\t\ttitle: \"Plugin Smith — 構文エラー\"\n\t\t\tbody: `生成結果に構文エラーがありました。修正用にクリップボードへ退避しました。{Str:lf}{Str:lf}{diag}`\n\t\t})\n\t\treturn null\n\t}\n\n\t// 確認ダイアログにソース全文 (is ハイライト) が表示される。\n\t// active:false で作成され handler は走らない。有効化はユーザーが手動で。\n\tNd:call('plugins.create', {\n\t\tname: name\n\t\tsrc: src\n\t\tauthor: \"@plugin-smith\"\n\t\tdescription: \"Plugin Smith が生成 (有効化前に内容を確認してください)\"\n\t})\n}\n\nNd:register_command(\n\t'plugin-smith-run'\n\t'Plugin Smith — AiScript 生成'\n\t'ti-tools'\n\t@() { generate() }\n\t{ permissions: ['ai.invoke', 'clipboard', 'plugins.read', 'plugins.write', 'notifications'] }\n)\n"} diff --git a/public/registry/plugins/plugin-smith/plugin.is b/public/registry/plugins/plugin-smith/plugin.is index e6d9cde..d2e9d31 100644 --- a/public/registry/plugins/plugin-smith/plugin.is +++ b/public/registry/plugins/plugin-smith/plugin.is @@ -72,7 +72,7 @@ "" "【NoteDeck の規約】" "- 冒頭に ### { name, version, author, description } メタブロックを置く" - "- コマンド登録は Nd:register_command(id, label, icon, handler, options)" + "- コマンド登録は Nd:register_command(id, label, icon, handler, options)。id に : は使えない (英数字とハイフンのみ)" "- AI 呼び出しは Nd:call('ai.chat', { prompt })" "- クリップボードは Nd:call('clipboard.read', {}) / Nd:call('clipboard.write', { text })" "- 通知は Nd:call('ui.notify', { title, body })" @@ -137,7 +137,7 @@ } Nd:register_command( - 'plugin-smith:run' + 'plugin-smith-run' 'Plugin Smith — AiScript 生成' 'ti-tools' @() { generate() }