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-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"
}
}
4 changes: 2 additions & 2 deletions public/registry/plugins.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"version": 1,
"updatedAt": "2026-08-07T01:20:05.144Z",
"updatedAt": "2026-08-11T04:14:55.998Z",
"plugins": [
{
"id": "plugin-smith",
Expand All @@ -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",
Expand Down
2 changes: 1 addition & 1 deletion public/registry/plugins/plugin-smith/api.json
Original file line number Diff line number Diff line change
@@ -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"}
4 changes: 2 additions & 2 deletions public/registry/plugins/plugin-smith/plugin.is
Original file line number Diff line number Diff line change
Expand Up @@ -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 })"
Expand Down Expand Up @@ -137,7 +137,7 @@
}

Nd:register_command(
'plugin-smith:run'
'plugin-smith-run'
'Plugin Smith — AiScript 生成'
'ti-tools'
@() { generate() }
Expand Down
Loading