Add complete ECS Fargate infrastructure for Clawdbot Discord bot deployment on AWS. ## Infrastructure (Terraform) - **VPC**: 100.64.0.0/16 with DNS support - **Public Subnets**: 2 subnets in different AZs - **ECR Repository**: clawdbot/bot with lifecycle policy - **IAM Roles**: Task Role (DynamoDB+S3) + Execution Role - **ECS Resources**: Fargate (256 CPU, 2048 MB memory) - **Security Group**: Outbound only - **CloudWatch**: Log group with 7-day retention ## Security Improvements - Discord Bot Token → AWS Secrets Manager - IAM policy with least privilege principle - No plaintext secrets in code ## Code Quality - Fix all 22 lint errors - Add *.d.ts to oxlint ignore patterns - Fix Dockerfile .buildstamp for Linux compatibility Closes #2049 Co-Authored-By: Claude <noreply@anthropic.com>
77 lines
2.4 KiB
JavaScript
77 lines
2.4 KiB
JavaScript
#!/usr/bin/env node
|
|
/**
|
|
* List Discord Channels
|
|
* サーバー内の全チャンネルを一覧表示
|
|
*/
|
|
|
|
import { listGuildChannelsDiscord } from "../src/discord/send.guild.js";
|
|
import { loadConfig } from "../src/config/config.js";
|
|
import { resolveDiscordAccount } from "../src/discord/accounts.js";
|
|
import { createDiscordClient } from "../src/discord/send.shared.js";
|
|
|
|
async function main() {
|
|
const GUILD_ID = "1260121338811514880"; // PPAL Server
|
|
|
|
const cfg = loadConfig();
|
|
const accountInfo = resolveDiscordAccount({ cfg, accountId: "ppal" });
|
|
const { token } = createDiscordClient({}, cfg);
|
|
|
|
console.log(`\n📋 Discord Server: ${GUILD_ID}`);
|
|
console.log(`🤖 Bot: ${accountInfo.accountId} (${accountInfo.config.name || "PPAL Bot"})\n`);
|
|
|
|
try {
|
|
const channels = await listGuildChannelsDiscord(GUILD_ID, { token });
|
|
|
|
console.log("📺 チャンネル一覧:\n");
|
|
console.log("".padEnd(25), "タイプ".padEnd(15), "ID");
|
|
console.log("=".repeat(70));
|
|
|
|
for (const channel of channels) {
|
|
const type =
|
|
channel.type === 0 ? "テキスト" :
|
|
channel.type === 2 ? "音声" :
|
|
channel.type === 4 ? "カテゴリ" :
|
|
channel.type === 5 ? " announcements" :
|
|
channel.type === 15 ? "forum" : `type_${channel.type}`;
|
|
|
|
const indent = channel.type === 4 ? "" : " ";
|
|
|
|
console.log(
|
|
`${indent}${(channel.name || "").padEnd(25)} ` +
|
|
`${type.padEnd(15)} ` +
|
|
`${channel.id}`
|
|
);
|
|
}
|
|
|
|
console.log("\n");
|
|
|
|
// テキストチャンネルのみ抽出
|
|
const textChannels = channels.filter(ch => ch.type === 0);
|
|
console.log(`\n📝 テキストチャンネル (${textChannels.length}件):\n`);
|
|
textChannels.forEach(ch => {
|
|
console.log(` #${ch.name} → ID: ${ch.id}`);
|
|
});
|
|
|
|
console.log("\n✅ おすすめの通知チャンネル:\n");
|
|
const generalChannel = textChannels.find(ch =>
|
|
ch.name.toLowerCase().includes("general") ||
|
|
ch.name.toLowerCase().includes("通知") ||
|
|
ch.name.toLowerCase().includes("notify")
|
|
);
|
|
|
|
if (generalChannel) {
|
|
console.log(` 👉 #${generalChannel.name} (ID: ${generalChannel.id})`);
|
|
} else if (textChannels.length > 0) {
|
|
console.log(` 👉 #${textChannels[0].name} (ID: ${textChannels[0].id})`);
|
|
}
|
|
|
|
console.log("");
|
|
|
|
} catch (error: any) {
|
|
console.error("❌ エラー:", error.message);
|
|
process.exit(1);
|
|
}
|
|
}
|
|
|
|
main();
|