UNPKG

kawazu

Version:

kawazu CLI tool for real-time chat in your editor

659 lines (641 loc) 33.6 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.getCodechatPath = getCodechatPath; exports.createCodechatFile = createCodechatFile; exports.createCodechatFileIfNotExists = createCodechatFileIfNotExists; exports.appendMessageToFile = appendMessageToFile; exports.readFileContent = readFileContent; exports.ensureDirectory = ensureDirectory; exports.isValidRoomSlug = isValidRoomSlug; exports.getCurrentRoomFromCodechat = getCurrentRoomFromCodechat; exports.getCodechatFiles = getCodechatFiles; exports.clearInputArea = clearInputArea; exports.createCommandHelpFile = createCommandHelpFile; exports.loadMessageHistory = loadMessageHistory; exports.loadMoreMessageHistory = loadMoreMessageHistory; const fs = __importStar(require("fs-extra")); const path = __importStar(require("path")); const node_fetch_1 = __importDefault(require("node-fetch")); const chalk_1 = __importDefault(require("chalk")); const message_1 = require("./message"); function getCodechatPath(roomSlug, workingDir = process.cwd()) { return path.join(workingDir, `${roomSlug}.codechat`); } async function createCodechatFile(filePath, roomSlug, username) { const initialContent = `================================================================================ File: ${roomSlug}.codechat ================================================================================ Room: ${roomSlug} User: ${username} Messages: 最新10件まで表示 💭 「チャットを開始しましょう!」 📜 過去のメッセージを読み込み中... ================================================================================ ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― メッセージを下の線上に書いて保存(Ctrl+S)してください ------------------------------------------------------------------------------> メッセージを上の線上に書き `; await fs.writeFile(filePath, initialContent, 'utf8'); // コマンドヘルプファイルを作成 await createCommandHelpFile(path.dirname(filePath), roomSlug); } // 新しい関数:ファイル存在チェック付きの安全な作成 async function createCodechatFileIfNotExists(filePath, roomSlug, username) { try { // ファイルの存在をチェック const fileExists = await fs.pathExists(filePath); if (fileExists) { console.log(`📄 既存のチャットファイルが見つかりました: ${path.basename(filePath)}`); // 既存ファイルのユーザー名を更新(必要に応じて) await updateUsernameInExistingFile(filePath, username); // コマンドヘルプファイルは常に最新にする await createCommandHelpFile(path.dirname(filePath), roomSlug); return { created: false, existed: true }; } else { console.log(`📝 新しいチャットファイルを作成中: ${path.basename(filePath)}`); await createCodechatFile(filePath, roomSlug, username); return { created: true, existed: false }; } } catch (error) { console.error('ファイル作成チェックエラー:', error); // エラーの場合は安全のため新しいファイルを作成 await createCodechatFile(filePath, roomSlug, username); return { created: true, existed: false }; } } // 既存ファイルのユーザー名を更新 async function updateUsernameInExistingFile(filePath, newUsername) { try { const content = await fs.readFile(filePath, 'utf8'); // ヘッダー部分のユーザー名を更新 const userLineRegex = /^ User: .+$/m; const updatedContent = content.replace(userLineRegex, ` User: ${newUsername}`); if (content !== updatedContent) { await fs.writeFile(filePath, updatedContent, 'utf8'); console.log(`👤 ファイル内のユーザー名を更新しました: ${newUsername}`); } } catch (error) { console.error('ユーザー名更新エラー:', error); // エラーは無視(ファイルが存在することが重要) } } async function appendMessageToFile(filePath, message) { try { console.log(`🔍 ファイル書き込み開始: ${path.basename(filePath)}`); console.log(`📝 追加するメッセージ: "${message.substring(0, 100)}${message.length > 100 ? '...' : ''}"`); // ファイルの内容を読み取り const currentContent = await fs.readFile(filePath, 'utf8'); console.log(`📂 現在のファイルサイズ: ${currentContent.length}文字`); // 新しい形式の境界を特定 const headerEnd = '================================================================================'; const inputLineStart = '------------------------------------------------------------------------------>'; const firstHeaderIndex = currentContent.indexOf(headerEnd); const secondHeaderIndex = currentContent.indexOf(headerEnd, firstHeaderIndex + 1); const thirdHeaderIndex = currentContent.indexOf(headerEnd, secondHeaderIndex + 1); const inputLineIndex = currentContent.lastIndexOf(inputLineStart); console.log(`🔍 ファイル構造解析:`, { firstHeaderIndex, secondHeaderIndex, thirdHeaderIndex, inputLineIndex, validStructure: firstHeaderIndex !== -1 && secondHeaderIndex !== -1 && thirdHeaderIndex !== -1 && inputLineIndex !== -1 }); if (firstHeaderIndex !== -1 && secondHeaderIndex !== -1 && thirdHeaderIndex !== -1 && inputLineIndex !== -1) { // ヘッダー部分 const headerPart = currentContent.substring(0, secondHeaderIndex + headerEnd.length); // 現在のメッセージ部分 const messagePart = currentContent.substring(secondHeaderIndex + headerEnd.length, thirdHeaderIndex); // フッター部分(入力エリア以降) const footerStart = currentContent.substring(thirdHeaderIndex); console.log(`🔍 ファイル構造分割完了:`, { headerLength: headerPart.length, messagePartLength: messagePart.length, footerLength: footerStart.length }); // 既存のメッセージを抽出 const existingMessages = extractMessagesFromContent(messagePart); console.log(`📜 既存メッセージ数: ${existingMessages.length}`); // 新しいメッセージを追加 existingMessages.push(message); console.log(chalk_1.default.green(`📝 メッセージ追加後: ${existingMessages.length}件`)); // 最新10件のみを保持 const limitedMessages = existingMessages.slice(-10); console.log(chalk_1.default.blue(`📊 制限後のメッセージ数: ${limitedMessages.length}件(最新10件まで表示)`)); console.log(`🔍 制限後の最初のメッセージ: "${limitedMessages[0]?.substring(0, 30)}..."`); console.log(`🔍 制限後の最後のメッセージ: "${limitedMessages[limitedMessages.length - 1]?.substring(0, 30)}..."`); // 新しいメッセージ部分を構築(最新メッセージが上に来るように逆順処理) const newMessagePart = buildMessageContentWithReverse(limitedMessages); console.log(`🔧 新しいメッセージ部分のサイズ: ${newMessagePart.length}文字`); // ファイル全体を再構築 const newContent = headerPart + '\n' + newMessagePart + '\n' + footerStart; console.log(`📄 新しいファイルサイズ: ${newContent.length}文字`); await fs.writeFile(filePath, newContent, 'utf8'); console.log(chalk_1.default.green(`✅ ファイル書き込み完了: ${path.basename(filePath)} (${limitedMessages.length}件の履歴を維持)`)); } else { console.error(`❌ ファイル形式が認識できません:`, { filePath, contentLength: currentContent.length, headerEndCount: (currentContent.match(new RegExp(headerEnd, 'g')) || []).length, inputLineCount: (currentContent.match(new RegExp(inputLineStart, 'g')) || []).length }); // フォールバック: メッセージを最後に追加 const fallbackContent = currentContent + '\n' + message; await fs.writeFile(filePath, fallbackContent, 'utf8'); console.log(`⚠️ フォールバック書き込み完了`); } } catch (error) { console.error(`❌ ファイル書き込みエラー:`, { filePath, message: message.substring(0, 100), error: error.message, stack: error.stack }); // 重要なエラーの場合は再スロー throw error; } } function extractMessagesFromContent(messageSection) { const messages = []; const lines = messageSection.split('\n'); let currentMessage = ''; let collectingMessage = false; console.log(`🔍 メッセージ抽出開始: ${lines.length}行を処理`); for (let i = 0; i < lines.length; i++) { const line = lines[i]; console.log(`🔍 処理中の行 ${i}: "${line}"`); // メッセージの開始を検出(名前 アイコン 時刻の形式) // より厳密なパターンマッチング const messageStartPattern = /^[^\s]+\s+[^\s]+\s+\d{1,2}:\d{2}/; const ansiPattern = /^\[[0-9;]+m[^\s]+\s+[^\s]+.*\[[0-9;]*m/; if (messageStartPattern.test(line) || ansiPattern.test(line)) { console.log(`🔍 メッセージ開始を検出: "${line}"`); // 前のメッセージを保存 if (currentMessage.trim()) { messages.push(currentMessage.trim()); console.log(`📝 メッセージ保存: "${currentMessage.trim().substring(0, 30)}..."`); } currentMessage = line; collectingMessage = true; } else if (collectingMessage && line.trim() !== '') { // メッセージの続きを追加(インデントされた行) currentMessage += '\n' + line; console.log(`📝 メッセージ続行: "${line}"`); } else if (collectingMessage && line.trim() === '') { // 空行でメッセージ終了 if (currentMessage.trim()) { messages.push(currentMessage.trim()); console.log(`📝 メッセージ終了・保存: "${currentMessage.trim().substring(0, 30)}..."`); } currentMessage = ''; collectingMessage = false; } } // 最後のメッセージを保存 if (currentMessage.trim()) { messages.push(currentMessage.trim()); console.log(`📝 最後のメッセージ保存: "${currentMessage.trim().substring(0, 30)}..."`); } // フィルタリング前後のメッセージ数を記録 const unfilteredCount = messages.length; const filteredMessages = messages.filter(msg => { const isValid = msg.length > 0 && !msg.includes('💭 チャットを開始しましょう!') && !msg.includes('💭 「チャットを開始しましょう!」') && !msg.includes('古いメッセージは自動削除されます'); if (!isValid) { console.log(`🗑️ フィルタで除外: "${msg.substring(0, 30)}..."`); } return isValid; }); console.log(`📊 メッセージ抽出結果: ${unfilteredCount}件 → ${filteredMessages.length}件`); return filteredMessages; } function extractExistingMessages(historySection) { const messages = []; const lines = historySection.split('\n'); let currentMessage = ''; let insideMessage = false; for (const line of lines) { // メッセージの開始を検出(┌─ で始まる行) if (line.includes('┌─') && !line.includes('チャット履歴')) { if (currentMessage.trim()) { messages.push(currentMessage.trim()); } currentMessage = line + '\n'; insideMessage = true; } else if (insideMessage) { currentMessage += line + '\n'; // メッセージの終了を検出(└─ で始まる行) if (line.includes('└─')) { messages.push(currentMessage.trim()); currentMessage = ''; insideMessage = false; } } } return messages.filter(msg => msg.length > 0 && !msg.includes('💭 チャットを開始しましょう!') && !msg.includes('💭 「チャットを開始しましょう!」')); } function buildMessageContent(messages) { if (messages.length === 0) { return '💭 「チャットを開始しましょう!」'; } // メッセージを最新順(新しいものを上)で表示するために逆順にする const reversedMessages = [...messages].reverse(); // 7つ以上のメッセージがある場合は、古いメッセージ削除の表示を追加 let content = ''; if (messages.length >= 7) { content += '▼ 古いメッセージは自動削除されます(7つまで表示、最新順)\n\n'; } // メッセージを追加(最新が上に来るように) for (let i = 0; i < reversedMessages.length; i++) { content += reversedMessages[i]; if (i < reversedMessages.length - 1) { content += '\n'; } } return content; } function buildMessageContentWithoutReverse(messages) { if (messages.length === 0) { return '💭 「チャットを開始しましょう!」'; } // 7つ以上のメッセージがある場合は、古いメッセージ削除の表示を追加 let content = ''; if (messages.length >= 7) { content += '▼ 古いメッセージは自動削除されます(7つまで表示、最新順)\n\n'; } // メッセージを追加(既に正しい順序なので逆順処理なし) for (let i = 0; i < messages.length; i++) { content += messages[i]; if (i < messages.length - 1) { content += '\n'; } } return content; } function buildMessageContentWithReverse(messages) { if (messages.length === 0) { return '💭 「チャットを開始しましょう!」'; } // 10件以上のメッセージがある場合は、古いメッセージ削除の表示を追加 let content = ''; if (messages.length >= 10) { content += '▼ 最新10件のメッセージを表示中(古いメッセージは自動削除されます)\n\n'; } else if (messages.length >= 5) { content += `▼ ${messages.length}件のメッセージ履歴を表示中\n\n`; } // メッセージを逆順で追加(最新メッセージが上に来るように) const reversedMessages = [...messages].reverse(); console.log(`🔄 メッセージ順序逆転: ${messages.length}件 → 最新が上`); for (let i = 0; i < reversedMessages.length; i++) { content += reversedMessages[i]; if (i < reversedMessages.length - 1) { content += '\n'; } } return content; } function buildChatHistory(messages) { const chatHistoryStart = '╔═ チャット履歴 ═════════════════════════════════════════════════════════════╗'; const chatHistoryEnd = '╚═══════════════════════════════════════════════════════════════════════════╝'; let historyContent = chatHistoryStart + '\n'; if (messages.length === 0) { // メッセージがない場合は初期状態 for (let i = 0; i < 18; i++) { if (i === 9) { historyContent += '║ 💭 「チャットを開始しましょう!」 ║\n'; } else { historyContent += '║ ║\n'; } } } else { // メッセージを最新順で表示(逆順処理は呼び出し側で実施済み前提) let lineCount = 0; const maxLines = 18; for (const message of messages) { const messageLines = message.split('\n'); // メッセージの前に空行を追加 if (lineCount > 0 && lineCount < maxLines) { historyContent += '║ ║\n'; lineCount++; } // メッセージを追加 for (const line of messageLines) { if (lineCount < maxLines) { historyContent += line + '\n'; lineCount++; } } } // 残りの行を空行で埋める while (lineCount < maxLines) { historyContent += '║ ║\n'; lineCount++; } } historyContent += chatHistoryEnd; return historyContent; } async function readFileContent(filePath) { try { return await fs.readFile(filePath, 'utf8'); } catch (error) { console.error('ファイル読み取りエラー:', error); return ''; } } async function ensureDirectory(dirPath) { await fs.ensureDir(dirPath); } function isValidRoomSlug(slug) { return /^[a-zA-Z0-9-_]+$/.test(slug); } async function getCurrentRoomFromCodechat() { try { const currentDir = process.cwd(); const files = await fs.readdir(currentDir); // .codechatファイルを探す const codechatFiles = files.filter(file => file.endsWith('.codechat')); if (codechatFiles.length === 0) { return null; } // 最初の.codechatファイルからルーム名を抽出 const codechatFile = codechatFiles[0]; const roomSlug = codechatFile.replace('.codechat', ''); return roomSlug; } catch (error) { console.error('ルーム情報取得エラー:', error); return null; } } async function getCodechatFiles() { try { const currentDir = process.cwd(); const files = await fs.readdir(currentDir); return files.filter(file => file.endsWith('.codechat')); } catch (error) { console.error('ファイル一覧取得エラー:', error); return []; } } async function clearInputArea(filePath) { try { const currentContent = await fs.readFile(filePath, 'utf8'); // 入力線の上の部分をクリア const inputLineStart = '------------------------------------------------------------------------------>'; const inputLineIndex = currentContent.lastIndexOf(inputLineStart); if (inputLineIndex !== -1) { // 入力線より前の部分を取得 const beforeInputLine = currentContent.substring(0, inputLineIndex); // 最後の区切り線(================)を見つける const lastSeparator = '================================================================================'; const lastSeparatorIndex = beforeInputLine.lastIndexOf(lastSeparator); if (lastSeparatorIndex !== -1) { const beforeMessages = beforeInputLine.substring(0, lastSeparatorIndex + lastSeparator.length); const inputArea = currentContent.substring(inputLineIndex); // 入力エリアをクリア(空行2つ + 入力線以降) const cleanContent = beforeMessages + '\n\n\n' + inputArea; await fs.writeFile(filePath, cleanContent, 'utf8'); } } } catch (error) { console.error('入力エリアクリアエラー:', error); } } async function createCommandHelpFile(dirPath, roomSlug) { const helpFilePath = path.join(dirPath, `${roomSlug}-commands.kawazu`); const helpContent = `================================================================================ Kawazu コマンドリファレンス - ${roomSlug} ================================================================================ 📋 基本操作: • メッセージ送信: .codechatファイルで編集後 Ctrl+S • チャット終了: Ctrl+C 🔧 利用可能なコマンド: 📁 ファイル共有: kawazu share /path/to/file.js └─ ファイルを他の参加者と共有(承認が必要) 👤 ユーザー情報: kawazu profile ユーザー名 └─ 指定ユーザーのプロフィールを表示 🏠 ルーム操作: kawazu list └─ 参加可能なルーム一覧を表示 kawazu create "新しいルーム名" └─ 新しいルームを作成 🔐 認証・プラン: kawazu login └─ Webアプリアカウントでログイン kawazu logout └─ ログアウト kawazu whoami └─ 現在のユーザー情報を表示 kawazu plan └─ サブスクリプションプラン情報を確認 💬 メッセージ形式: • プレーンテキスト • コードブロック: \`\`\`言語名 で開始 • 絵文字対応 📊 制限事項: • メッセージ履歴: 50件まで(古いものは自動削除、SNSのように過去のメッセージも表示) • ファイル共有: プランに応じた容量制限 • ルーム作成数: プランに応じた制限 ================================================================================ `; await fs.writeFile(helpFilePath, helpContent, 'utf8'); console.log(`📖 コマンドヘルプファイルを作成しました: ${roomSlug}-commands.kawazu`); } // メッセージ履歴を取得してファイルに反映する関数(SNSのように全履歴を表示) async function loadMessageHistory(codechatFile, roomSlug, serverUrl, limit = 50 // 入室時に十分なメッセージを取得 ) { try { console.log(chalk_1.default.blue('📜 メッセージ履歴を取得中...')); console.log(chalk_1.default.gray(`🔍 API URL: ${serverUrl}/api/messages/${roomSlug}?limit=${limit}`)); // サーバーからメッセージ履歴を取得 const response = await (0, node_fetch_1.default)(`${serverUrl}/api/messages/${roomSlug}?limit=${limit}`, { method: 'GET', headers: { 'Content-Type': 'application/json' } }); console.log(chalk_1.default.gray(`🔍 API応答ステータス: ${response.status}`)); if (!response.ok) { const errorText = await response.text(); console.log(chalk_1.default.yellow('⚠️ メッセージ履歴の取得に失敗しました (サーバー応答: ' + response.status + ')')); console.log(chalk_1.default.gray(' エラー詳細:', errorText)); return; } const result = await response.json(); console.log(chalk_1.default.gray('🔍 API応答:', JSON.stringify(result, null, 2))); if (!result.success || !result.data || !result.data.messages) { console.log(chalk_1.default.yellow('⚠️ メッセージ履歴が見つかりませんでした')); console.log(chalk_1.default.gray(' 応答構造:', { success: result.success, hasData: !!result.data, hasMessages: !!(result.data && result.data.messages) })); return; } const messages = result.data.messages; if (messages.length === 0) { console.log(chalk_1.default.gray('💭 まだメッセージがありません')); return; } console.log(chalk_1.default.green(`📜 ${messages.length}件のメッセージ履歴を取得しました`)); // メッセージを適切な形式にフォーマット const formattedMessages = []; for (const message of messages) { const formattedMessage = (0, message_1.formatMessage)(message.username, message.content, message.created_at, false // 履歴のメッセージは他人のメッセージとして扱う ); formattedMessages.push(formattedMessage); } // 既存のファイル内容を読み取り const currentContent = await fs.readFile(codechatFile, 'utf8'); // ファイルの構造を解析 const headerEnd = '================================================================================'; const inputLineStart = '------------------------------------------------------------------------------>'; const firstHeaderIndex = currentContent.indexOf(headerEnd); const secondHeaderIndex = currentContent.indexOf(headerEnd, firstHeaderIndex + 1); const thirdHeaderIndex = currentContent.indexOf(headerEnd, secondHeaderIndex + 1); const inputLineIndex = currentContent.lastIndexOf(inputLineStart); if (firstHeaderIndex !== -1 && secondHeaderIndex !== -1 && thirdHeaderIndex !== -1 && inputLineIndex !== -1) { // ヘッダー部分 const headerPart = currentContent.substring(0, secondHeaderIndex + headerEnd.length); // フッター部分(入力エリア以降) const footerStart = currentContent.substring(thirdHeaderIndex); // 最新10件のメッセージを取得 const limitedMessages = formattedMessages.slice(-10); console.log(chalk_1.default.blue(`📊 履歴読み込み: ${formattedMessages.length}件 → ${limitedMessages.length}件を表示(最新10件まで表示)`)); // メッセージ部分を構築(最新メッセージが上に来るように) const messageContent = buildMessageContentWithReverse(limitedMessages); // ファイル全体を再構築 const newContent = headerPart + '\n' + messageContent + '\n' + footerStart; await fs.writeFile(codechatFile, newContent, 'utf8'); console.log(chalk_1.default.green(`✅ メッセージ履歴をファイルに反映しました (${limitedMessages.length}件の履歴を表示)`)); } else { console.log(chalk_1.default.yellow('⚠️ ファイル形式が予期した構造と異なります')); } } catch (error) { console.log(chalk_1.default.yellow(`⚠️ メッセージ履歴の取得中にエラーが発生しました: ${error.message}`)); console.log(chalk_1.default.gray('新しいメッセージの投稿は正常に動作します')); } } // 追加のメッセージ履歴を取得する関数(「もっと読み込む」機能) async function loadMoreMessageHistory(codechatFile, roomSlug, serverUrl, offset = 0, limit = 100) { try { console.log(chalk_1.default.blue(`📜 追加のメッセージ履歴を取得中(${offset}件目から${limit}件)...`)); // サーバーからメッセージ履歴を取得(オフセット付き) const response = await (0, node_fetch_1.default)(`${serverUrl}/api/messages/${roomSlug}?limit=${limit}&offset=${offset}`, { method: 'GET', headers: { 'Content-Type': 'application/json' } }); if (!response.ok) { console.log(chalk_1.default.yellow('⚠️ 追加メッセージ履歴の取得に失敗しました (サーバー応答: ' + response.status + ')')); return; } const result = await response.json(); if (!result.success || !result.data || !result.data.messages) { console.log(chalk_1.default.yellow('⚠️ 追加メッセージ履歴が見つかりませんでした')); return; } const newMessages = result.data.messages; if (newMessages.length === 0) { console.log(chalk_1.default.gray('💭 これ以上古いメッセージはありません')); return; } console.log(chalk_1.default.green(`📜 ${newMessages.length}件の追加メッセージ履歴を取得しました`)); // 既存のファイル内容を読み取り const currentContent = await fs.readFile(codechatFile, 'utf8'); // 既存のメッセージを抽出 const headerEnd = '================================================================================'; const inputLineStart = '------------------------------------------------------------------------------>'; const firstHeaderIndex = currentContent.indexOf(headerEnd); const secondHeaderIndex = currentContent.indexOf(headerEnd, firstHeaderIndex + 1); const thirdHeaderIndex = currentContent.indexOf(headerEnd, secondHeaderIndex + 1); const inputLineIndex = currentContent.lastIndexOf(inputLineStart); if (firstHeaderIndex !== -1 && secondHeaderIndex !== -1 && thirdHeaderIndex !== -1 && inputLineIndex !== -1) { // ヘッダー部分 const headerPart = currentContent.substring(0, secondHeaderIndex + headerEnd.length); // 現在のメッセージ部分 const currentMessagePart = currentContent.substring(secondHeaderIndex + headerEnd.length, thirdHeaderIndex); // フッター部分(入力エリア以降) const footerStart = currentContent.substring(thirdHeaderIndex); // 既存のメッセージを抽出 const existingMessages = extractMessagesFromContent(currentMessagePart); // 新しいメッセージを適切な形式にフォーマット const formattedNewMessages = []; for (const message of newMessages) { const formattedMessage = (0, message_1.formatMessage)(message.username, message.content, message.created_at, false); formattedNewMessages.push(formattedMessage); } // 古いメッセージを既存のメッセージの前に追加 const allMessages = [...formattedNewMessages, ...existingMessages]; // 最新100件まで保持(ファイルサイズ制限を考慮) const limitedMessages = allMessages.slice(-100); console.log(chalk_1.default.blue(`📊 追加読み込み後: ${allMessages.length}件 → ${limitedMessages.length}件を表示`)); // メッセージ部分を構築 const messageContent = buildMessageContentWithReverse(limitedMessages); // ファイル全体を再構築 const newContent = headerPart + '\n' + messageContent + '\n' + footerStart; await fs.writeFile(codechatFile, newContent, 'utf8'); console.log(chalk_1.default.green(`✅ 追加メッセージ履歴をファイルに反映しました (${newMessages.length}件の古いメッセージを追加)`)); } else { console.log(chalk_1.default.yellow('⚠️ ファイル形式が予期した構造と異なります')); } } catch (error) { console.log(chalk_1.default.yellow(`⚠️ 追加メッセージ履歴の取得中にエラーが発生しました: ${error.message}`)); } }