Files
hakorune/tools/codex-tmux-driver/codex-claude-auto-bridge.js

146 lines
4.2 KiB
JavaScript
Raw Permalink Normal View History

// codex-claude-auto-bridge.js
// CodexとClaudeを自動で橋渡しするシステム
const fs = require('fs').promises;
const path = require('path');
const TmuxCodexController = require('./tmux-codex-controller');
const CodexOutputWatcher = require('./codex-output-watcher');
class CodexClaudeAutoBridge {
constructor(config = {}) {
this.config = {
sessionName: config.sessionName || 'codex-safe',
outputFile: config.outputFile || './codex-response.txt',
logFile: config.logFile || './bridge.log',
watchInterval: config.watchInterval || 500,
...config
};
this.controller = new TmuxCodexController(this.config.sessionName);
this.watcher = new CodexOutputWatcher(this.config.sessionName);
this.isRunning = false;
}
// ブリッジを開始
async start() {
console.log('🌉 Starting Codex-Claude Auto Bridge...');
this.isRunning = true;
// 出力ウォッチャーのイベント設定
this.watcher.on('response', async (response) => {
await this.handleCodexResponse(response);
});
this.watcher.on('ready', () => {
console.log('💚 Codex is ready for next input');
});
// 監視開始
this.watcher.start(this.config.watchInterval);
await this.log('Bridge started');
}
// Codexの応答を処理
async handleCodexResponse(response) {
console.log('\n📝 Got Codex response!');
// 応答をファイルに保存Claudeが読めるように
await this.saveResponse(response);
// ログに記録
await this.log(`Codex response: ${response.substring(0, 100)}...`);
// 通知
console.log('✅ Response saved to:', this.config.outputFile);
console.log('📢 Please read the response file and send next message to Codex!');
// 自動応答モードの場合(オプション)
if (this.config.autoReply) {
await this.sendAutoReply();
}
}
// 応答をファイルに保存
async saveResponse(response) {
const timestamp = new Date().toISOString();
const content = `=== Codex Response at ${timestamp} ===\n\n${response}\n\n`;
await fs.writeFile(this.config.outputFile, content);
}
// Codexにメッセージを送信
async sendToCodex(message) {
console.log(`📤 Sending to Codex: "${message}"`);
await this.controller.sendKeys(message, true); // Enterも送る
await this.log(`Sent to Codex: ${message}`);
}
// 自動応答(実験的)
async sendAutoReply() {
// 簡単な自動応答ロジック
const replies = [
"なるほど!それについてもう少し詳しく教えて",
"いい感じだにゃ!次はどうする?",
"了解!他に何か提案はある?"
];
const reply = replies[Math.floor(Math.random() * replies.length)];
console.log(`🤖 Auto-replying in 3 seconds: "${reply}"`);
setTimeout(async () => {
await this.sendToCodex(reply);
}, 3000);
}
// ログ記録
async log(message) {
const timestamp = new Date().toISOString();
const logEntry = `[${timestamp}] ${message}\n`;
await fs.appendFile(this.config.logFile, logEntry);
}
// 停止
stop() {
this.watcher.stop();
this.isRunning = false;
console.log('🛑 Bridge stopped');
}
}
// CLIとして使う場合
if (require.main === module) {
const bridge = new CodexClaudeAutoBridge({
outputFile: './codex-response.txt',
autoReply: false // 自動応答は無効
});
// 引数からメッセージを取得
const initialMessage = process.argv.slice(2).join(' ');
async function run() {
// ブリッジ開始
await bridge.start();
// 初期メッセージがあれば送信
if (initialMessage) {
console.log('📨 Sending initial message...');
await bridge.sendToCodex(initialMessage);
} else {
console.log('💡 Send a message to Codex using:');
console.log(' tmux send-keys -t codex-safe "your message" Enter');
}
// Ctrl+Cで終了
process.on('SIGINT', () => {
console.log('\n👋 Shutting down...');
bridge.stop();
process.exit(0);
});
}
run().catch(console.error);
}
module.exports = CodexClaudeAutoBridge;