dual-brain 4.2.0 → 4.5.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 +130 -35
- package/README.md +171 -44
- package/hooks/agent-chains.mjs +369 -0
- package/hooks/agent-templates.mjs +441 -0
- package/hooks/atomic-write.mjs +5 -3
- package/hooks/config-validator.mjs +156 -0
- package/hooks/confirmation-policy.mjs +167 -0
- package/hooks/cost-logger.mjs +32 -12
- package/hooks/cost-report.mjs +60 -114
- package/hooks/decision-ledger.mjs +3 -2
- package/hooks/dual-brain-review.mjs +249 -2
- package/hooks/dual-brain-think.mjs +294 -25
- package/hooks/enforce-tier.mjs +246 -87
- package/hooks/error-channel.mjs +68 -0
- package/hooks/failure-detector.mjs +2 -1
- package/hooks/health-check.mjs +16 -17
- package/hooks/risk-classifier.mjs +135 -2
- package/hooks/session-report.mjs +41 -71
- package/hooks/ship-captain.mjs +1176 -0
- package/hooks/ship-gate.mjs +971 -0
- package/hooks/summary-checkpoint.mjs +31 -4
- package/hooks/test-orchestrator.mjs +1975 -11
- package/install.mjs +1064 -31
- package/orchestrator.json +73 -96
- package/package.json +7 -2
|
@@ -3,12 +3,21 @@
|
|
|
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 Claude provides its own independent analysis, and both
|
|
7
|
+
* perspectives are synthesized into a final recommendation.
|
|
8
8
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
9
|
+
* Auto mode (default — no --round flag):
|
|
10
|
+
* Runs the full 2-round collaboration automatically in one command.
|
|
11
|
+
* node .claude/hooks/dual-brain-think.mjs --question "Should we use Redis?"
|
|
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
|
|
12
21
|
*
|
|
13
22
|
* Usage as module:
|
|
14
23
|
* import { dualThink } from './dual-brain-think.mjs';
|
|
@@ -27,6 +36,7 @@ import { fileURLToPath } from 'url';
|
|
|
27
36
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
28
37
|
|
|
29
38
|
const CODEX_TIMEOUT_MS = 120_000;
|
|
39
|
+
const CLAUDE_TIMEOUT_MS = 60_000;
|
|
30
40
|
const MODEL = 'gpt-5.5';
|
|
31
41
|
|
|
32
42
|
// ---------------------------------------------------------------------------
|
|
@@ -56,6 +66,30 @@ function findCodex() {
|
|
|
56
66
|
return null;
|
|
57
67
|
}
|
|
58
68
|
|
|
69
|
+
// ---------------------------------------------------------------------------
|
|
70
|
+
// Claude CLI discovery
|
|
71
|
+
// ---------------------------------------------------------------------------
|
|
72
|
+
|
|
73
|
+
function findClaude() {
|
|
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;
|
|
91
|
+
}
|
|
92
|
+
|
|
59
93
|
// ---------------------------------------------------------------------------
|
|
60
94
|
// Prompt builder
|
|
61
95
|
// ---------------------------------------------------------------------------
|
|
@@ -161,6 +195,102 @@ function runGptAnalysis(codexBin, prompt) {
|
|
|
161
195
|
};
|
|
162
196
|
}
|
|
163
197
|
|
|
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
|
+
|
|
164
294
|
// ---------------------------------------------------------------------------
|
|
165
295
|
// Usage logger — matches schema_version: 2 used across the orchestrator
|
|
166
296
|
// ---------------------------------------------------------------------------
|
|
@@ -276,6 +406,131 @@ export async function dualThink({ question, context, files, round, claudePerspec
|
|
|
276
406
|
};
|
|
277
407
|
}
|
|
278
408
|
|
|
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
|
+
|
|
279
534
|
// ---------------------------------------------------------------------------
|
|
280
535
|
// CLI argument parser
|
|
281
536
|
// ---------------------------------------------------------------------------
|
|
@@ -312,7 +567,7 @@ function parseArgs(argv) {
|
|
|
312
567
|
}
|
|
313
568
|
|
|
314
569
|
// ---------------------------------------------------------------------------
|
|
315
|
-
// CLI output formatter
|
|
570
|
+
// CLI output formatter (manual mode)
|
|
316
571
|
// ---------------------------------------------------------------------------
|
|
317
572
|
|
|
318
573
|
function printResult(result, question) {
|
|
@@ -323,23 +578,23 @@ function printResult(result, question) {
|
|
|
323
578
|
const roundLabel = result.round === 2 ? 'Round 2 — Rebuttal' : 'Round 1 — Initial';
|
|
324
579
|
|
|
325
580
|
console.log(TOP);
|
|
326
|
-
console.log(`║
|
|
581
|
+
console.log(`║ Dual-Brain Think · ${roundLabel}`.padEnd(51) + '║');
|
|
327
582
|
console.log(BAR);
|
|
328
583
|
const q = question.length > 44 ? question.slice(0, 41) + '...' : question;
|
|
329
584
|
console.log(`║ Question: ${q.padEnd(38)} ║`);
|
|
330
585
|
console.log(BAR);
|
|
331
586
|
|
|
332
587
|
if (!result.gpt) {
|
|
333
|
-
console.log(`║
|
|
588
|
+
console.log(`║ ${(result.error || 'Unknown error').padEnd(46)} ║`);
|
|
334
589
|
console.log(BAR);
|
|
335
|
-
console.log(`║
|
|
590
|
+
console.log(`║ ${(result.fallback || '').padEnd(46)} ║`);
|
|
336
591
|
console.log(BOT);
|
|
337
592
|
return;
|
|
338
593
|
}
|
|
339
594
|
|
|
340
595
|
const gptData = result.gpt;
|
|
341
596
|
const durSec = (gptData.durationMs / 1000).toFixed(1);
|
|
342
|
-
console.log(`║
|
|
597
|
+
console.log(`║ GPT-5.5 (${durSec}s):`.padEnd(51) + '║');
|
|
343
598
|
console.log(BAR);
|
|
344
599
|
console.log('');
|
|
345
600
|
console.log(gptData.recommendation || gptData.rebuttal);
|
|
@@ -347,13 +602,13 @@ function printResult(result, question) {
|
|
|
347
602
|
console.log(BAR);
|
|
348
603
|
|
|
349
604
|
if (result.round === 2) {
|
|
350
|
-
console.log('║
|
|
351
|
-
console.log('║ Where you agree → high confidence.
|
|
352
|
-
console.log('║ Where you disagree → state what would resolve
|
|
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. ║');
|
|
353
608
|
} else {
|
|
354
|
-
console.log('║
|
|
355
|
-
console.log('║
|
|
356
|
-
console.log('║
|
|
609
|
+
console.log('║ Your turn: analyze independently, then call ║');
|
|
610
|
+
console.log('║ Round 2 with --round 2 --claude-says "..." ║');
|
|
611
|
+
console.log('║ for GPT\'s rebuttal to your analysis. ║');
|
|
357
612
|
}
|
|
358
613
|
console.log(BOT);
|
|
359
614
|
}
|
|
@@ -368,18 +623,32 @@ if (import.meta.url === `file://${process.argv[1]}`) {
|
|
|
368
623
|
if (!args.question) {
|
|
369
624
|
console.error(
|
|
370
625
|
'Usage: node dual-brain-think.mjs --question "<question>" [--context "<ctx>"] [--files f1,f2]\n' +
|
|
371
|
-
' node dual-brain-think.mjs --question "<question>" --round 2 --claude-says "<analysis>"'
|
|
626
|
+
' node dual-brain-think.mjs --question "<question>" --round 2 --claude-says "<analysis>"\n' +
|
|
627
|
+
' node dual-brain-think.mjs --question "<question>" --manual (force old 1-step flow)'
|
|
372
628
|
);
|
|
373
629
|
process.exit(1);
|
|
374
630
|
}
|
|
375
631
|
|
|
376
|
-
const
|
|
377
|
-
|
|
378
|
-
context: args.context,
|
|
379
|
-
files: args.files,
|
|
380
|
-
round: args.round ? parseInt(args.round, 10) : 1,
|
|
381
|
-
claudePerspective: args['claude-says'] || null,
|
|
382
|
-
});
|
|
632
|
+
const hasExplicitRound = args.round !== undefined;
|
|
633
|
+
const isManual = args.manual === true || hasExplicitRound;
|
|
383
634
|
|
|
384
|
-
|
|
635
|
+
if (!isManual) {
|
|
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
|
+
}
|
|
385
654
|
}
|