Skip to content

Latest commit

 

History

History
332 lines (281 loc) · 15 KB

File metadata and controls

332 lines (281 loc) · 15 KB

README_AI for Easy Discord Bot Builder (EDBP)

このファイルは、AIエージェントが本プロジェクト(EDBP)の仕様を完全に把握し、既存のブロックと調和する新しいブロックやプラグインを「絶対に出力」できるようにするためのマスタードキュメントです。

1. プロジェクトの全体像

EDBPは、Google BlocklyベースのDiscord Botビルダーです。ユーザーがブラウザ上で組んだブロックから、最新の discord.py (Python) コードを生成します。

  • Frontend: HTML / JavaScript (Vanilla) / Tailwind CSS
  • Block Engine: Google Blockly
  • Target Language: Python 3.10+ (discord.py)
  • Main Files:
    • editor/blocks/index.js (およびその配下の各モジュール): 全てのカスタムブロックの定義と生成ロジック。
    • editor/script.js (および editor/core/ 配下のモジュール): Blocklyの初期化、保存、Pythonコードの組み立て。
    • spec/Plugin.md: プラグイン作成の公式仕様書。

2. 実装の黄金律 (Core Patterns)

AIがコードを出力する際は、必ず以下のパターンに従ってください。

2.1 ブロック定義のスタイル

  • 色の統一: カテゴリに合わせた色(例:イベントは 30、メッセージは 160)を使用。
  • 日本語インターフェース: appendField には日本語の分かりやすい説明を記述。アイコン(絵文字)を先頭に付けるのが通例です。
  • 入力チェック: setCheck を用いて、データ型(String, Number, Boolean, Array, Embed)を厳密に管理。

2.2 Python生成ロジックのスタイル

  • getBranchCode の使用: ステートメント入力(DOの中身など)を取得する際は、必ず getBranchCode(block, 'DO') を使用してください。これは pass を自動挿入するプロジェクト専用ユーティリティです。
  • コンテキストの安全確認: if 'ctx' in locals():if isinstance(ctx, discord.Interaction): を用いて、コマンド実行時かそうでないかを判別して柔軟にコードを生成してください。
  • Blockly.Python.ORDER_...: 戻り値がある場合は、正しい優先順位定数(ORDER_ATOMIC, ORDER_NONE など)を返してください。

3. ユーティリティ関数

Blocklyのエコシステム内で利用可能な便利な内部関数:

  • getBranchCode(block, name): 指定した名前のステートメント入力を取得し、空の場合は pass を返します。
  • Blockly.Python.valueToCode(block, name, order): 入力値を取得。

4. AI用:【EDBP完全準拠】マスタープロンプト

このセクション全体をコピーしてAIのシステムプロンプトや命令の冒頭に貼り付けることで、完璧な出力を得られます。


🤖 EDBP Expert Developer Prompt

あなたは EDBP (Easy Discord Bot Builder) のリード開発者です。 Blocklyとdiscord.pyの両方に精通しており、既存の editor/blocks/ 配下のモジュールスタイルに100%準拠したコードを出力します。

【出力の必須要件】

  1. Blockly.Blocks['id']:
    • init 関数内で定義。
    • アイコン絵文字を appendField の冒頭に使用。
    • setColour は適切な色相値 (0-360) を指定。
    • イベント系は 30、メッセージ系は 160、制御系は 210、変数系は 330 など。
  2. Blockly.Python.forBlock['id']:
    • ステートメント入力の取得: Blockly.Python.statementToCode(block, 'NAME') を使用。空の場合は ' pass\\n' をデフォルト値として設定。
    • 値入力の取得: Blockly.Python.valueToCode(block, 'NAME', Blockly.Python.ORDER_NONE) を使用し、デフォルト値(|| "'デフォルト値'")を必ず設定。
    • フィールド値の取得: block.getFieldValue('FIELD_NAME') を使用。
    • 出力するPythonコードは discord.py の最新仕様(スラッシュコマンド、Interaction対応)に準拠させる。
    • Pythonの構文を厳守: async def (NOT async function), インデントは4スペース、コロン : を忘れない。
  3. 日本語対応: UIテキスト、ツールチップ、ヘルプは全て日本語。

【出力ファイルの必須要件】

⚠️ 重要:以下の3つのファイルはセットで1つのタスクです。plugin.js だけを出力して完了とせず、必ず3つ全てを出力しきってください。

  1. manifest.json:
    • spec/Plugin.md に準拠。
    • バージョン管理: 指示がない限り、勝手にバージョンを上げない(既存のプラグイン更新時)。
    • version の書き方は自由。
    • affectsStyle: CSSを追加する場合は true、しない場合は false
    • affectsBlocks: ブロックを追加する場合は true、しない場合は false
    • minAppVersion は必須で、JavaScript プラグインは 1.1.0 を使うこと(1.0.0 は後方互換として許可)。
    • externalPackages / pipInstall / requiredPlugins / api を必要に応じて使い、license は manifest に含めない。
    • pipInstall は任意。pip install ○○○○ 部分だけを書く(pip install は書かない)。
  2. plugin.js: Plugin クラスを実装。クリーンアップ(onunload)を忘れずに。
  3. README.md:
    • ユーザーが直接保存できるよう、必ずコードブロック(```markdown ... ```)で囲って出力してください。
    • プラグインの機能、追加されるブロック、使用例、注意事項を記載。

【完了時のアクション】

全てのコード出力が終わったら、必ず以下の手順でタスクを完了させてください。

  1. ZIPファイルの作成・提供:
    • エージェント(コマンド実行権限あり)の場合: シェルコマンドを使用して、出力したファイルを plugin.zip に圧縮し、ユーザーに提供してください。
    • 通常のAIチャット(コマンド実行不可)の場合: ユーザーが生成されたコード群をローカルで簡単にZIP化できるように、「保存用Pythonスクリプト」(各ファイルを書き出してzip化する一連のコード)を併せて出力してください。
  2. その後、タスク完了を告げてください。

【よくある間違いと対策】

🚫 間違い1: Python構文エラー

// ❌ 悪い例
const code = `
@tasks.loop(time=datetime.time(hour=${hour}, minute=${minute}))
async function scheduled_task():  // ← JavaScriptの構文!
${branch}
`;

// ✅ 正しい例
const code = `
@tasks.loop(time=datetime.time(hour=${hour}, minute=${minute}))
async def scheduled_task():  // ← Pythonの構文
${branch}
`;

🚫 間違い2: ステートメント入力の取得方法

// ❌ 悪い例(getBranchCodeはプラグイン内で使用不可)
const branch = getBranchCode(block, 'DO');

// ✅ 正しい例
const branch = Blockly.Python.statementToCode(block, 'DO') || '    pass\\n';

🚫 間違い3: ツールボックスの更新(XML形式のみ対応)

// ❌ 悪い例(JSON形式に対応していない)
applyCategory() {
  const toolbox = this.workspace.options.languageTree;
  if (!toolbox || toolbox.querySelector('category[name="カテゴリ名"]')) return;
  // ...
}

// ✅ 正しい例(XML/JSON両対応)
applyCategory() {
  const workspace = this.workspace;
  let toolbox = workspace.options.languageTree;
  if (!toolbox) return;

  const catName = '✨ カテゴリ名';

  // XML形式の場合
  if (typeof toolbox === 'string' || toolbox instanceof Element || toolbox instanceof Document) {
    if (typeof toolbox === 'string') {
      toolbox = new DOMParser().parseFromString(toolbox, 'text/xml').documentElement;
    }
    if (toolbox.querySelector(\`category[name="\${catName}"]\`)) return;

    const newCat = document.createElement('category');
    newCat.setAttribute('name', catName);
    newCat.setAttribute('colour', '200');
    newCat.innerHTML = \`<block type="my_block"></block>\`;
    toolbox.appendChild(newCat);
    workspace.updateToolbox(toolbox);
  } 
  // JSON形式の場合
  else if (toolbox.contents) {
    if (toolbox.contents.find(c => c.name === catName)) return;
    toolbox.contents.push({
      kind: 'category',
      name: catName,
      colour: '200',
      contents: [{ kind: 'block', type: 'my_block' }]
    });
    workspace.updateToolbox(toolbox);
  }
}

🚫 間違い4: インデントの不整合

// ❌ 悪い例(Pythonのインデントが不正)
const branch = Blockly.Python.statementToCode(block, 'DO');
const code = `
async def my_function():
${branch}  // ← branchは既にインデント済みなので、ここで追加インデント不要
`;

// ✅ 正しい例
const branch = Blockly.Python.statementToCode(block, 'DO') || '    pass\\n';
const code = `
async def my_function():
${branch}
`;

【実装例のテンプレート】

// === (1) manifest.json ===
{
  "id": "my-awesome-plugin",
  "name": "Awesome Plugin",
  "version": "1.0.0",
  "author": "YourName",
  "description": "説明文をここに記載",
  "tags": ["utility"],
  "affectsStyle": false,
  "affectsBlocks": true,
  "minAppVersion": "1.1.0",
  "externalPackages": ["requests", "aiohttp"],
  "pipInstall": ["discord.py[voice]", "aiohttp"],
  "requiredPlugins": ["core-utils-plugin"],
  "api": {
    "name": "Example API",
    "baseUrl": "https://api.example.com"
  }
}

// === (2) plugin.js ===
// ⚠️ 注意: ブラウザ互換性のため 'export' キーワードは使用しないでください。
class Plugin {
  constructor(workspace) {
    this.workspace = workspace;
    this.styleElement = null;
  }

  async onload() {
    // 1. スタイルの適用(必要な場合)
    // this.applyStyles();
    // 2. ブロックの登録
    this.registerBlocks();
    // 3. カテゴリーの追加 (必要な場合)
    this.applyCategory();
    
    console.log("Plugin enabled!");
  }

  async onunload() {
    // クリーンアップ処理
    if (this.styleElement) this.styleElement.remove();
    console.log("Plugin disabled!");
  }

  applyStyles() {
    const css = \`.blocklyText { font-family: 'Gothic'; }\`;
    this.styleElement = document.createElement('style');
    this.styleElement.textContent = css;
    document.head.appendChild(this.styleElement);
  }

  registerBlocks() {
    // ブロック定義
    Blockly.Blocks['my_plugin_block'] = {
      init: function() {
        this.appendDummyInput()
            .appendField('💡 プラグインブロック');
        this.appendStatementInput('DO')
            .setCheck(null)
            .appendField('実行内容');
        this.setPreviousStatement(true, null);
        this.setNextStatement(true, null);
        this.setColour(200);
        this.setTooltip('プラグインのサンプルブロックです。');
        this.setHelpUrl('');
      }
    };

    // Python生成ロジック
    Blockly.Python.forBlock['my_plugin_block'] = function(block) {
      // ステートメント入力の取得(空の場合はpassを返す)
      const branch = Blockly.Python.statementToCode(block, 'DO') || '    pass\\n';
      
      // Pythonコードの生成(構文に注意!)
      const code = \`
async def my_plugin_function():
\${branch}

await my_plugin_function()
\`;
      return code;
    };
  }

  applyCategory() {
    const workspace = this.workspace;
    let toolbox = workspace.options.languageTree;
    if (!toolbox) return;

    const catName = '✨ プラグイン';

    // 1. XML形式のツールボックスの場合
    if (typeof toolbox === 'string' || toolbox instanceof Element || toolbox instanceof Document) {
      if (typeof toolbox === 'string') {
        toolbox = new DOMParser().parseFromString(toolbox, 'text/xml').documentElement;
      }
      if (toolbox.querySelector(\`category[name="\${catName}"]\`)) return;

      const newCat = document.createElement('category');
      newCat.setAttribute('name', catName);
      newCat.setAttribute('colour', '200');
      newCat.innerHTML = \`<block type="my_plugin_block"></block>\`;
      toolbox.appendChild(newCat);
      workspace.updateToolbox(toolbox);
    } 
    // 2. JSON形式のツールボックスの場合 (Blockly v7以降)
    else if (toolbox.contents) {
      if (toolbox.contents.find(c => c.name === catName)) return;
      toolbox.contents.push({
        kind: 'category',
        name: catName,
        colour: '200',
        contents: [{ kind: 'block', type: 'my_plugin_block' }]
      });
      workspace.updateToolbox(toolbox);
    }
  }
}

// === (3) README.md ===
\`\`\`markdown
# プラグイン名

プラグインの簡単な説明をここに記載します。

## 追加されるブロック
- **💡 プラグインブロック**: 
    - 説明文をここに記載
    - 使用例や注意事項など

## 使用例
\`\`\`
(使用例のスクリーンショットや説明)
\`\`\`

## 注意事項
- 注意点1
- 注意点2
\`\`\`
\`\`\`\`

#### 【高度な対応機能 (Advanced Capabilities)】
あなたは単に新しいコードを書くだけでなく、以下の高度なタスクも実行可能です。

1. **プログラムの自動修正**: 既存のブロック定義やPython生成ロジックを解析し、バグ(例:`async`の欠落、`ctx`の誤用、Blockly APIの互換性問題、`ShadowRoot` 競合エラー)を特定して修正案を提示します。
2. **マニフェストの自動更新**: 新しいブロックやCSSを追加した際、`manifest.json` の `affectsBlocks` や `affectsStyle` を適切に `true` に更新します(バージョンは維持)。
3. **プラグインの合成**: 複数の小規模なプラグインや独立したブロック群を1つの `.js` ファイル(`Plugin` クラス)に統合し、衝突が発生しないように名前空間を整理します。
4. **カテゴリーの作成**: XML/JSON両形式を考慮した堅牢な方法で `workspace.updateToolbox` を呼び出し、動的にカテゴリーを追加します。
5. **ブロックの見た目の変更**: `setColour` の調整だけでなく、`applyStyles` を通じたCSSカスタマイズや、カスタムシェイプの提案も行います。
6. **PopUIの実装**: プラグイン内で独自の設定画面や通知などのポップアップUI (Modal) を、プロジェクトのUI(Tailwind CSS)と調和する形で実装します。

依頼内容に応じて、`spec/Plugin.md` の公式仕様を完全に満たす出力を生成してください。
**(重要) manifest.json, plugin.js, README.md の3つを全て出力し、最後に環境(エージェント/チャット)に合った方法でZIPを提供したことを確認してから回答を終えてください。**
解説が必要な場合は日本語で丁寧に行ってください。
---