dual-brain 4.6.0 → 4.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +35 -130
- package/README.md +34 -179
- package/hooks/control-panel.mjs +379 -8
- package/hooks/cost-logger.mjs +11 -53
- package/hooks/cost-report.mjs +126 -65
- package/hooks/decision-ledger.mjs +3 -53
- package/hooks/dual-brain-review.mjs +25 -261
- package/hooks/dual-brain-think.mjs +37 -300
- package/hooks/enforce-tier.mjs +93 -265
- package/hooks/failure-detector.mjs +1 -3
- package/hooks/gpt-work-dispatcher.mjs +153 -12
- package/hooks/health-check.mjs +25 -17
- package/hooks/quality-gate.mjs +11 -6
- package/hooks/risk-classifier.mjs +2 -135
- package/hooks/session-report.mjs +71 -41
- package/hooks/summary-checkpoint.mjs +8 -35
- package/hooks/test-orchestrator.mjs +31 -2080
- package/install.mjs +616 -1564
- package/orchestrator.json +96 -73
- package/package.json +2 -7
- package/hooks/agent-chains.mjs +0 -369
- package/hooks/agent-templates.mjs +0 -441
- package/hooks/atomic-write.mjs +0 -109
- package/hooks/config-validator.mjs +0 -156
- package/hooks/confirmation-policy.mjs +0 -167
- package/hooks/error-channel.mjs +0 -68
- package/hooks/ship-captain.mjs +0 -1176
- package/hooks/ship-gate.mjs +0 -971
|
@@ -3,21 +3,12 @@
|
|
|
3
3
|
* dual-brain-think.mjs
|
|
4
4
|
*
|
|
5
5
|
* Runs a dual-perspective thinking process — GPT-5.5 (via Codex CLI) independently
|
|
6
|
-
* analyzes a question, then
|
|
7
|
-
*
|
|
6
|
+
* analyzes a question, then emits its output along with instructions for Claude
|
|
7
|
+
* (the main session) to provide its own independent analysis and compare both.
|
|
8
8
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* Manual Round 1:
|
|
14
|
-
* node .claude/hooks/dual-brain-think.mjs --question "..." --round 1
|
|
15
|
-
*
|
|
16
|
-
* Manual Round 2:
|
|
17
|
-
* node .claude/hooks/dual-brain-think.mjs --question "..." --round 2 --claude-says "<analysis>"
|
|
18
|
-
*
|
|
19
|
-
* Force manual mode (skip auto):
|
|
20
|
-
* node .claude/hooks/dual-brain-think.mjs --question "..." --manual
|
|
9
|
+
* Usage as CLI:
|
|
10
|
+
* node .claude/hooks/dual-brain-think.mjs \
|
|
11
|
+
* --question "Should we use queues or direct API calls for the notification system?"
|
|
21
12
|
*
|
|
22
13
|
* Usage as module:
|
|
23
14
|
* import { dualThink } from './dual-brain-think.mjs';
|
|
@@ -28,7 +19,7 @@
|
|
|
28
19
|
* });
|
|
29
20
|
*/
|
|
30
21
|
|
|
31
|
-
import {
|
|
22
|
+
import { spawnSync } from 'child_process';
|
|
32
23
|
import { appendFileSync } from 'fs';
|
|
33
24
|
import { dirname, join } from 'path';
|
|
34
25
|
import { fileURLToPath } from 'url';
|
|
@@ -36,7 +27,6 @@ import { fileURLToPath } from 'url';
|
|
|
36
27
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
37
28
|
|
|
38
29
|
const CODEX_TIMEOUT_MS = 120_000;
|
|
39
|
-
const CLAUDE_TIMEOUT_MS = 60_000;
|
|
40
30
|
const MODEL = 'gpt-5.5';
|
|
41
31
|
|
|
42
32
|
// ---------------------------------------------------------------------------
|
|
@@ -66,28 +56,11 @@ function findCodex() {
|
|
|
66
56
|
return null;
|
|
67
57
|
}
|
|
68
58
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
try {
|
|
75
|
-
const which = spawnSync('which', ['claude'], { encoding: 'utf8', stdio: 'pipe', timeout: 3000 });
|
|
76
|
-
if (which.status === 0 && which.stdout.trim()) return which.stdout.trim();
|
|
77
|
-
} catch {}
|
|
78
|
-
const home = process.env.HOME || process.env.USERPROFILE || '';
|
|
79
|
-
const fallbacks = [
|
|
80
|
-
join(home, '.local', 'bin', 'claude'),
|
|
81
|
-
join(home, 'bin', 'claude'),
|
|
82
|
-
'/usr/local/bin/claude',
|
|
83
|
-
];
|
|
84
|
-
for (const p of fallbacks) {
|
|
85
|
-
try {
|
|
86
|
-
const res = spawnSync(p, ['--version'], { stdio: 'pipe', timeout: 3000 });
|
|
87
|
-
if (res.status === 0) return p;
|
|
88
|
-
} catch {}
|
|
89
|
-
}
|
|
90
|
-
return null;
|
|
59
|
+
function isCodexAuthenticated(result) {
|
|
60
|
+
const out = ((result?.stdout || '') + (result?.stderr || '')).toLowerCase();
|
|
61
|
+
if (/\b(not\s+logged\s+in|unauthenticated|logged\s+out|no\s+auth)\b/.test(out)) return false;
|
|
62
|
+
return result?.status === 0 ||
|
|
63
|
+
/\b(logged\s+in|authenticated|signed\s+in)\b/.test(out);
|
|
91
64
|
}
|
|
92
65
|
|
|
93
66
|
// ---------------------------------------------------------------------------
|
|
@@ -195,102 +168,6 @@ function runGptAnalysis(codexBin, prompt) {
|
|
|
195
168
|
};
|
|
196
169
|
}
|
|
197
170
|
|
|
198
|
-
// ---------------------------------------------------------------------------
|
|
199
|
-
// Claude CLI executor
|
|
200
|
-
// ---------------------------------------------------------------------------
|
|
201
|
-
|
|
202
|
-
function runClaudeAnalysis(claudeBin, question, context) {
|
|
203
|
-
const prompt = `You are providing an independent analysis for a dual-brain architecture discussion. Question: ${question}${context ? `\n\nContext: ${context}` : ''}
|
|
204
|
-
|
|
205
|
-
Provide:
|
|
206
|
-
1) Your recommendation (clear, 1-2 sentences)
|
|
207
|
-
2) Key alternatives considered
|
|
208
|
-
3) Risks with your recommendation
|
|
209
|
-
4) Verification approach
|
|
210
|
-
|
|
211
|
-
Be concise — under 300 words.`;
|
|
212
|
-
|
|
213
|
-
const startTime = Date.now();
|
|
214
|
-
|
|
215
|
-
const proc = spawnSync(claudeBin, ['-p', prompt], {
|
|
216
|
-
encoding: 'utf8',
|
|
217
|
-
stdio: ['pipe', 'pipe', 'pipe'],
|
|
218
|
-
timeout: CLAUDE_TIMEOUT_MS,
|
|
219
|
-
});
|
|
220
|
-
|
|
221
|
-
const durationMs = Date.now() - startTime;
|
|
222
|
-
|
|
223
|
-
if (proc.status === 0 && proc.stdout && proc.stdout.trim()) {
|
|
224
|
-
return {
|
|
225
|
-
success: true,
|
|
226
|
-
text: proc.stdout.trim(),
|
|
227
|
-
durationMs,
|
|
228
|
-
};
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
return {
|
|
232
|
-
success: false,
|
|
233
|
-
error: proc.stderr?.slice(0, 200) || 'Claude CLI returned no output',
|
|
234
|
-
durationMs,
|
|
235
|
-
};
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
// ---------------------------------------------------------------------------
|
|
239
|
-
// Synthesis builder — pattern-based, no AI call
|
|
240
|
-
// ---------------------------------------------------------------------------
|
|
241
|
-
|
|
242
|
-
function buildSynthesis(gptR1Text, claudeText, gptR2Text) {
|
|
243
|
-
const lines = [];
|
|
244
|
-
|
|
245
|
-
lines.push('SYNTHESIS');
|
|
246
|
-
lines.push('─'.repeat(50));
|
|
247
|
-
|
|
248
|
-
// Extract agreements from GPT Round 2 AGREEMENTS section
|
|
249
|
-
const agreementsMatch = gptR2Text.match(/AGREEMENTS?[:\s\n]+([\s\S]*?)(?=\n\s*(?:PUSHBACK|NEW INSIGHTS|REFINED|REMAINING|CONFIDENCE|[0-9]+\.)|$)/i);
|
|
250
|
-
if (agreementsMatch) {
|
|
251
|
-
lines.push('');
|
|
252
|
-
lines.push('AGREEMENTS (both aligned):');
|
|
253
|
-
lines.push(agreementsMatch[1].trim().split('\n').slice(0, 4).join('\n'));
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
// Extract pushback / disagreements from GPT Round 2
|
|
257
|
-
const pushbackMatch = gptR2Text.match(/PUSHBACK[:\s\n]+([\s\S]*?)(?=\n\s*(?:NEW INSIGHTS|REFINED|REMAINING|CONFIDENCE|[0-9]+\.)|$)/i);
|
|
258
|
-
if (pushbackMatch && pushbackMatch[1].trim().length > 10) {
|
|
259
|
-
lines.push('');
|
|
260
|
-
lines.push('DISAGREEMENTS (review carefully):');
|
|
261
|
-
lines.push(pushbackMatch[1].trim().split('\n').slice(0, 4).join('\n'));
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
// Extract refined recommendation from GPT Round 2
|
|
265
|
-
const refinedMatch = gptR2Text.match(/REFINED RECOMMENDATION[:\s\n]+([\s\S]*?)(?=\n\s*(?:REMAINING|CONFIDENCE|[0-9]+\.)|$)/i);
|
|
266
|
-
if (refinedMatch) {
|
|
267
|
-
lines.push('');
|
|
268
|
-
lines.push('RECOMMENDED ACTION:');
|
|
269
|
-
lines.push(refinedMatch[1].trim().split('\n').slice(0, 3).join('\n'));
|
|
270
|
-
} else {
|
|
271
|
-
// Fall back to R1 recommendation
|
|
272
|
-
const r1RecMatch = gptR1Text.match(/RECOMMENDATION[:\s\n]+([\s\S]*?)(?=\n\s*(?:RATIONALE|ALTERNATIVES|RISKS|CONFIDENCE|[0-9]+\.)|$)/i);
|
|
273
|
-
if (r1RecMatch) {
|
|
274
|
-
lines.push('');
|
|
275
|
-
lines.push('RECOMMENDED ACTION (from Round 1):');
|
|
276
|
-
lines.push(r1RecMatch[1].trim().split('\n').slice(0, 2).join('\n'));
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
// Confidence note
|
|
281
|
-
const confDeltaMatch = gptR2Text.match(/CONFIDENCE DELTA[:\s\n]+([\s\S]*?)(?=\n\s*[0-9]+\.|$)/i);
|
|
282
|
-
if (confDeltaMatch) {
|
|
283
|
-
lines.push('');
|
|
284
|
-
lines.push('CONFIDENCE NOTE:');
|
|
285
|
-
lines.push(confDeltaMatch[1].trim().split('\n').slice(0, 2).join('\n'));
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
lines.push('');
|
|
289
|
-
lines.push('─'.repeat(50));
|
|
290
|
-
|
|
291
|
-
return lines.join('\n');
|
|
292
|
-
}
|
|
293
|
-
|
|
294
171
|
// ---------------------------------------------------------------------------
|
|
295
172
|
// Usage logger — matches schema_version: 2 used across the orchestrator
|
|
296
173
|
// ---------------------------------------------------------------------------
|
|
@@ -340,13 +217,12 @@ export async function dualThink({ question, context, files, round, claudePerspec
|
|
|
340
217
|
};
|
|
341
218
|
}
|
|
342
219
|
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
} catch {
|
|
220
|
+
const login = spawnSync(codexBin, ['login', 'status'], {
|
|
221
|
+
encoding: 'utf8',
|
|
222
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
223
|
+
timeout: 5000,
|
|
224
|
+
});
|
|
225
|
+
if (!isCodexAuthenticated(login)) {
|
|
350
226
|
return {
|
|
351
227
|
gpt: null,
|
|
352
228
|
error: 'Codex CLI not authenticated — run `codex login`',
|
|
@@ -406,131 +282,6 @@ export async function dualThink({ question, context, files, round, claudePerspec
|
|
|
406
282
|
};
|
|
407
283
|
}
|
|
408
284
|
|
|
409
|
-
// ---------------------------------------------------------------------------
|
|
410
|
-
// Auto mode — full 2-round collaboration in one command
|
|
411
|
-
// ---------------------------------------------------------------------------
|
|
412
|
-
|
|
413
|
-
async function runAutoMode({ question, context, files }) {
|
|
414
|
-
const BAR = '╠══════════════════════════════════════════════════╣';
|
|
415
|
-
const TOP = '╔══════════════════════════════════════════════════╗';
|
|
416
|
-
const BOT = '╚══════════════════════════════════════════════════╝';
|
|
417
|
-
const WIDE = '║';
|
|
418
|
-
|
|
419
|
-
const qShort = question.length > 44 ? question.slice(0, 41) + '...' : question;
|
|
420
|
-
|
|
421
|
-
console.log(TOP);
|
|
422
|
-
console.log(`${WIDE} Dual-Brain Think — Auto Mode`.padEnd(51) + WIDE);
|
|
423
|
-
console.log(BAR);
|
|
424
|
-
console.log(`${WIDE} Question: ${qShort.padEnd(38)} ${WIDE}`);
|
|
425
|
-
console.log(BOT);
|
|
426
|
-
console.log('');
|
|
427
|
-
|
|
428
|
-
// Step 1: Check Codex
|
|
429
|
-
const codexBin = findCodex();
|
|
430
|
-
if (!codexBin) {
|
|
431
|
-
console.log('[Auto mode] Codex CLI not found — falling back to manual mode.');
|
|
432
|
-
console.log('');
|
|
433
|
-
console.log('Manual steps:');
|
|
434
|
-
console.log(` 1. Run: node hooks/dual-brain-think.mjs --question "${question}" --round 1`);
|
|
435
|
-
console.log(` 2. Analyze independently`);
|
|
436
|
-
console.log(` 3. Run: node hooks/dual-brain-think.mjs --question "${question}" --round 2 --claude-says "<your analysis>"`);
|
|
437
|
-
return;
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
try {
|
|
441
|
-
execSync(`${codexBin} login status`, {
|
|
442
|
-
encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'], timeout: 5000,
|
|
443
|
-
});
|
|
444
|
-
} catch {
|
|
445
|
-
console.log('[Auto mode] Codex not authenticated (run `codex login`) — falling back to manual mode.');
|
|
446
|
-
console.log('');
|
|
447
|
-
console.log('Manual steps:');
|
|
448
|
-
console.log(` 1. Run: node hooks/dual-brain-think.mjs --question "${question}" --round 1`);
|
|
449
|
-
console.log(` 2. Analyze independently`);
|
|
450
|
-
console.log(` 3. Run: node hooks/dual-brain-think.mjs --question "${question}" --round 2 --claude-says "<your analysis>"`);
|
|
451
|
-
return;
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
// Step 2: Round 1 — GPT analysis
|
|
455
|
-
console.log('[ 1/4 ] Sending to GPT for Round 1 analysis...');
|
|
456
|
-
const r1Prompt = buildGptPrompt({ question, context, files, round: 1 });
|
|
457
|
-
const r1Raw = runGptAnalysis(codexBin, r1Prompt);
|
|
458
|
-
logUsage({ durationMs: r1Raw.durationMs, usage: r1Raw.usage, success: r1Raw.success });
|
|
459
|
-
|
|
460
|
-
if (!r1Raw.success) {
|
|
461
|
-
console.log(`[Auto mode] GPT Round 1 failed: ${r1Raw.error}`);
|
|
462
|
-
console.log('Falling back to manual mode — see instructions above.');
|
|
463
|
-
return;
|
|
464
|
-
}
|
|
465
|
-
|
|
466
|
-
console.log('');
|
|
467
|
-
console.log(TOP);
|
|
468
|
-
console.log(`${WIDE} Round 1 — GPT Analysis (${(r1Raw.durationMs / 1000).toFixed(1)}s)`.padEnd(51) + WIDE);
|
|
469
|
-
console.log(BOT);
|
|
470
|
-
console.log('');
|
|
471
|
-
console.log(r1Raw.text);
|
|
472
|
-
console.log('');
|
|
473
|
-
|
|
474
|
-
// Step 3: Claude's independent analysis
|
|
475
|
-
const claudeBin = findClaude();
|
|
476
|
-
let claudeText = null;
|
|
477
|
-
|
|
478
|
-
if (!claudeBin) {
|
|
479
|
-
console.log('[Auto mode] Claude CLI not found — skipping Claude analysis step.');
|
|
480
|
-
console.log('Set your PATH to include the `claude` binary to enable full auto mode.');
|
|
481
|
-
console.log('');
|
|
482
|
-
} else {
|
|
483
|
-
console.log('[ 2/4 ] Generating Claude independent analysis...');
|
|
484
|
-
const claudeRaw = runClaudeAnalysis(claudeBin, question, context);
|
|
485
|
-
|
|
486
|
-
if (!claudeRaw.success) {
|
|
487
|
-
console.log(`[Auto mode] Claude analysis failed: ${claudeRaw.error}`);
|
|
488
|
-
console.log('Continuing with GPT Round 2 without Claude perspective.');
|
|
489
|
-
console.log('');
|
|
490
|
-
} else {
|
|
491
|
-
claudeText = claudeRaw.text;
|
|
492
|
-
console.log('');
|
|
493
|
-
console.log(TOP);
|
|
494
|
-
console.log(`${WIDE} Claude Independent Analysis (${(claudeRaw.durationMs / 1000).toFixed(1)}s)`.padEnd(51) + WIDE);
|
|
495
|
-
console.log(BOT);
|
|
496
|
-
console.log('');
|
|
497
|
-
console.log(claudeText);
|
|
498
|
-
console.log('');
|
|
499
|
-
}
|
|
500
|
-
}
|
|
501
|
-
|
|
502
|
-
// Step 4: Round 2 — GPT rebuttal
|
|
503
|
-
const claudePerspective = claudeText || '(Claude analysis unavailable — review independently)';
|
|
504
|
-
console.log('[ 3/4 ] Sending Round 2 to GPT with Claude perspective...');
|
|
505
|
-
const r2Prompt = buildGptPrompt({ question, context, files, round: 2, claudePerspective });
|
|
506
|
-
const r2Raw = runGptAnalysis(codexBin, r2Prompt);
|
|
507
|
-
logUsage({ durationMs: r2Raw.durationMs, usage: r2Raw.usage, success: r2Raw.success });
|
|
508
|
-
|
|
509
|
-
if (!r2Raw.success) {
|
|
510
|
-
console.log(`[Auto mode] GPT Round 2 failed: ${r2Raw.error}`);
|
|
511
|
-
console.log('Synthesis skipped — review Round 1 and Claude analysis above.');
|
|
512
|
-
return;
|
|
513
|
-
}
|
|
514
|
-
|
|
515
|
-
console.log('');
|
|
516
|
-
console.log(TOP);
|
|
517
|
-
console.log(`${WIDE} Round 2 — GPT Rebuttal (${(r2Raw.durationMs / 1000).toFixed(1)}s)`.padEnd(51) + WIDE);
|
|
518
|
-
console.log(BOT);
|
|
519
|
-
console.log('');
|
|
520
|
-
console.log(r2Raw.text);
|
|
521
|
-
console.log('');
|
|
522
|
-
|
|
523
|
-
// Step 5: Synthesis
|
|
524
|
-
console.log('[ 4/4 ] Building synthesis...');
|
|
525
|
-
console.log('');
|
|
526
|
-
console.log(TOP);
|
|
527
|
-
console.log(`${WIDE} Final Synthesis`.padEnd(51) + WIDE);
|
|
528
|
-
console.log(BOT);
|
|
529
|
-
console.log('');
|
|
530
|
-
console.log(buildSynthesis(r1Raw.text, claudeText || '', r2Raw.text));
|
|
531
|
-
console.log('');
|
|
532
|
-
}
|
|
533
|
-
|
|
534
285
|
// ---------------------------------------------------------------------------
|
|
535
286
|
// CLI argument parser
|
|
536
287
|
// ---------------------------------------------------------------------------
|
|
@@ -567,7 +318,7 @@ function parseArgs(argv) {
|
|
|
567
318
|
}
|
|
568
319
|
|
|
569
320
|
// ---------------------------------------------------------------------------
|
|
570
|
-
// CLI output formatter
|
|
321
|
+
// CLI output formatter
|
|
571
322
|
// ---------------------------------------------------------------------------
|
|
572
323
|
|
|
573
324
|
function printResult(result, question) {
|
|
@@ -578,23 +329,23 @@ function printResult(result, question) {
|
|
|
578
329
|
const roundLabel = result.round === 2 ? 'Round 2 — Rebuttal' : 'Round 1 — Initial';
|
|
579
330
|
|
|
580
331
|
console.log(TOP);
|
|
581
|
-
console.log(`║ Dual-Brain Think · ${roundLabel}`.padEnd(51) + '║');
|
|
332
|
+
console.log(`║ 🧠 Dual-Brain Think · ${roundLabel}`.padEnd(51) + '║');
|
|
582
333
|
console.log(BAR);
|
|
583
334
|
const q = question.length > 44 ? question.slice(0, 41) + '...' : question;
|
|
584
335
|
console.log(`║ Question: ${q.padEnd(38)} ║`);
|
|
585
336
|
console.log(BAR);
|
|
586
337
|
|
|
587
338
|
if (!result.gpt) {
|
|
588
|
-
console.log(`║
|
|
339
|
+
console.log(`║ ❌ ${(result.error || 'Unknown error').padEnd(45)} ║`);
|
|
589
340
|
console.log(BAR);
|
|
590
|
-
console.log(`║
|
|
341
|
+
console.log(`║ ↩️ ${(result.fallback || '').padEnd(45)} ║`);
|
|
591
342
|
console.log(BOT);
|
|
592
343
|
return;
|
|
593
344
|
}
|
|
594
345
|
|
|
595
346
|
const gptData = result.gpt;
|
|
596
347
|
const durSec = (gptData.durationMs / 1000).toFixed(1);
|
|
597
|
-
console.log(`║ GPT-5.5 (${durSec}s):`.padEnd(51) + '║');
|
|
348
|
+
console.log(`║ 🤖 GPT-5.5 (${durSec}s):`.padEnd(51) + '║');
|
|
598
349
|
console.log(BAR);
|
|
599
350
|
console.log('');
|
|
600
351
|
console.log(gptData.recommendation || gptData.rebuttal);
|
|
@@ -602,13 +353,13 @@ function printResult(result, question) {
|
|
|
602
353
|
console.log(BAR);
|
|
603
354
|
|
|
604
355
|
if (result.round === 2) {
|
|
605
|
-
console.log('║ Synthesize both rounds into final decision.
|
|
606
|
-
console.log('║ Where you agree → high confidence.
|
|
607
|
-
console.log('║ Where you disagree → state what would resolve
|
|
356
|
+
console.log('║ 🔄 Synthesize both rounds into final decision. ║');
|
|
357
|
+
console.log('║ Where you agree → high confidence. ║');
|
|
358
|
+
console.log('║ Where you disagree → state what would resolve it.║');
|
|
608
359
|
} else {
|
|
609
|
-
console.log('║ Your turn: analyze independently, then call
|
|
610
|
-
console.log('║
|
|
611
|
-
console.log('║
|
|
360
|
+
console.log('║ 📝 Your turn: analyze independently, then call ║');
|
|
361
|
+
console.log('║ Round 2 with --round 2 --claude-says "..." ║');
|
|
362
|
+
console.log('║ for GPT\'s rebuttal to your analysis. ║');
|
|
612
363
|
}
|
|
613
364
|
console.log(BOT);
|
|
614
365
|
}
|
|
@@ -623,32 +374,18 @@ if (import.meta.url === `file://${process.argv[1]}`) {
|
|
|
623
374
|
if (!args.question) {
|
|
624
375
|
console.error(
|
|
625
376
|
'Usage: node dual-brain-think.mjs --question "<question>" [--context "<ctx>"] [--files f1,f2]\n' +
|
|
626
|
-
' node dual-brain-think.mjs --question "<question>" --round 2 --claude-says "<analysis>"
|
|
627
|
-
' node dual-brain-think.mjs --question "<question>" --manual (force old 1-step flow)'
|
|
377
|
+
' node dual-brain-think.mjs --question "<question>" --round 2 --claude-says "<analysis>"'
|
|
628
378
|
);
|
|
629
379
|
process.exit(1);
|
|
630
380
|
}
|
|
631
381
|
|
|
632
|
-
const
|
|
633
|
-
|
|
382
|
+
const result = await dualThink({
|
|
383
|
+
question: args.question,
|
|
384
|
+
context: args.context,
|
|
385
|
+
files: args.files,
|
|
386
|
+
round: args.round ? parseInt(args.round, 10) : 1,
|
|
387
|
+
claudePerspective: args['claude-says'] || null,
|
|
388
|
+
});
|
|
634
389
|
|
|
635
|
-
|
|
636
|
-
// Auto mode: full 2-round collaboration in one shot
|
|
637
|
-
await runAutoMode({
|
|
638
|
-
question: args.question,
|
|
639
|
-
context: args.context,
|
|
640
|
-
files: args.files,
|
|
641
|
-
});
|
|
642
|
-
} else {
|
|
643
|
-
// Manual mode: original single-round behavior
|
|
644
|
-
const result = await dualThink({
|
|
645
|
-
question: args.question,
|
|
646
|
-
context: args.context,
|
|
647
|
-
files: args.files,
|
|
648
|
-
round: args.round ? parseInt(args.round, 10) : 1,
|
|
649
|
-
claudePerspective: args['claude-says'] || null,
|
|
650
|
-
});
|
|
651
|
-
|
|
652
|
-
printResult(result, args.question);
|
|
653
|
-
}
|
|
390
|
+
printResult(result, args.question);
|
|
654
391
|
}
|