dual-brain 0.3.34 → 0.3.36
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/bin/dual-brain.mjs +109 -9
- package/package.json +1 -1
package/bin/dual-brain.mjs
CHANGED
|
@@ -6,6 +6,7 @@ import { join, dirname, basename, extname } from 'node:path';
|
|
|
6
6
|
import { fileURLToPath } from 'node:url';
|
|
7
7
|
import { execSync, spawnSync as _spawnSyncTop } from 'node:child_process';
|
|
8
8
|
import { createInterface } from 'node:readline';
|
|
9
|
+
import { randomUUID } from 'node:crypto';
|
|
9
10
|
|
|
10
11
|
import {
|
|
11
12
|
ensureProfile, loadProfile, saveProfile, runOnboarding,
|
|
@@ -68,6 +69,22 @@ function _codexResumeArgs(sessionId, cwd) {
|
|
|
68
69
|
];
|
|
69
70
|
}
|
|
70
71
|
|
|
72
|
+
function _codexNewArgs(cwd) {
|
|
73
|
+
const workspace = cwd || process.cwd();
|
|
74
|
+
if (getEffectiveBypassPermissions(workspace)) {
|
|
75
|
+
return ['--dangerously-bypass-approvals-and-sandbox'];
|
|
76
|
+
}
|
|
77
|
+
const settings = loadSessionSettings(workspace);
|
|
78
|
+
const approvalMode = getEffectiveAutomode(loadProfile(workspace), workspace) ? 'never' : 'on-request';
|
|
79
|
+
return [
|
|
80
|
+
..._codexModelEffortArgs(
|
|
81
|
+
_modelMatchesProvider(settings.headModel, 'codex') ? settings.headModel : null,
|
|
82
|
+
settings.effort,
|
|
83
|
+
),
|
|
84
|
+
..._codexApprovalArgs(workspace, approvalMode),
|
|
85
|
+
];
|
|
86
|
+
}
|
|
87
|
+
|
|
71
88
|
function _isReplitWorkspace(cwd) {
|
|
72
89
|
const workspace = cwd || process.cwd();
|
|
73
90
|
return !!(
|
|
@@ -1552,6 +1569,10 @@ async function cmdRuntimeSwitch(args = []) {
|
|
|
1552
1569
|
? runtimeLaunchArgsForPending(sess, cwd, pending)
|
|
1553
1570
|
: ['handoff', '--to', provider];
|
|
1554
1571
|
|
|
1572
|
+
const activeForSwitch = confirmed ? readActiveConversation(cwd) : null;
|
|
1573
|
+
const activeMatches = activeForSwitch?.sessionId === sess.id;
|
|
1574
|
+
let restartSignaled = false;
|
|
1575
|
+
|
|
1555
1576
|
console.log('');
|
|
1556
1577
|
console.log(`Runtime switch ${confirmed ? 'confirmed' : 'prepared'} for ${pending?.sessionName || sess.id}`);
|
|
1557
1578
|
console.log(`Provider: ${provider}`);
|
|
@@ -1561,10 +1582,16 @@ async function cmdRuntimeSwitch(args = []) {
|
|
|
1561
1582
|
console.log(`Reason: ${reason}`);
|
|
1562
1583
|
console.log(`Launch: ${provider} ${launchArgs.join(' ')}`);
|
|
1563
1584
|
if (confirmed) {
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1585
|
+
if (activeMatches) {
|
|
1586
|
+
restartSignaled = signalActiveConversation(cwd, sess.id);
|
|
1587
|
+
if (restartSignaled) {
|
|
1588
|
+
const terminalNote = activeForSwitch.terminalId && activeForSwitch.terminalId !== getTerminalId()
|
|
1589
|
+
? ` in ${activeForSwitch.terminalId}`
|
|
1590
|
+
: '';
|
|
1591
|
+
console.log(`Active supervisor detected${terminalNote}: restart signal sent.`);
|
|
1592
|
+
} else {
|
|
1593
|
+
console.log('Active supervisor was detected, but the restart signal could not be delivered.');
|
|
1594
|
+
}
|
|
1568
1595
|
} else if (!args.includes('--apply')) {
|
|
1569
1596
|
console.log('No active supervisor detected: saved for the next dual-brain resume/switch, not live yet.');
|
|
1570
1597
|
}
|
|
@@ -1573,7 +1600,12 @@ async function cmdRuntimeSwitch(args = []) {
|
|
|
1573
1600
|
|
|
1574
1601
|
if (args.includes('--apply')) {
|
|
1575
1602
|
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
1576
|
-
|
|
1603
|
+
if (restartSignaled) {
|
|
1604
|
+
console.log('Non-interactive shell detected: command applied by signaling the active dual-brain terminal.');
|
|
1605
|
+
} else {
|
|
1606
|
+
console.log('Non-interactive shell detected: saved for the next dual-brain resume/switch.');
|
|
1607
|
+
console.log('This command cannot mutate an unattached API/chat surface that is already running under another provider.');
|
|
1608
|
+
}
|
|
1577
1609
|
} else {
|
|
1578
1610
|
const applied = await processPendingRuntimeSwitch(cwd);
|
|
1579
1611
|
if (!applied) console.log('Could not apply live here; resume the session through dual-brain to use these settings.');
|
|
@@ -4780,11 +4812,79 @@ async function mainScreen(rl, ask) {
|
|
|
4780
4812
|
|
|
4781
4813
|
async function newSessionScreen(rl, ask) {
|
|
4782
4814
|
const cwd = process.cwd();
|
|
4783
|
-
const
|
|
4784
|
-
|
|
4815
|
+
const profile = loadProfile(cwd);
|
|
4816
|
+
const settings = loadSessionSettings(cwd);
|
|
4817
|
+
settings.automode = true;
|
|
4818
|
+
settings.bypassPermissions = false;
|
|
4785
4819
|
|
|
4786
|
-
|
|
4787
|
-
|
|
4820
|
+
let provider = _modelMatchesProvider(settings.headModel, 'claude') ? 'claude' : 'codex';
|
|
4821
|
+
if (!_modelMatchesProvider(settings.headModel, provider)) {
|
|
4822
|
+
const policy = _headPolicyFor(provider, profile, settings);
|
|
4823
|
+
settings.headModel = policy.model;
|
|
4824
|
+
settings.effort = policy.effort;
|
|
4825
|
+
}
|
|
4826
|
+
saveSessionSettings(cwd, settings);
|
|
4827
|
+
|
|
4828
|
+
const renderStart = () => {
|
|
4829
|
+
const policy = _headPolicyFor(provider, profile, settings);
|
|
4830
|
+
if (!_modelMatchesProvider(settings.headModel, provider)) {
|
|
4831
|
+
settings.headModel = policy.model;
|
|
4832
|
+
settings.effort = policy.effort;
|
|
4833
|
+
saveSessionSettings(cwd, settings);
|
|
4834
|
+
}
|
|
4835
|
+
process.stdout.write('\n');
|
|
4836
|
+
process.stdout.write(' New HEAD Conversation\n\n');
|
|
4837
|
+
process.stdout.write(' Recommended Balanced Session\n');
|
|
4838
|
+
process.stdout.write(` Provider: ${provider === 'codex' ? 'GPT/Codex' : 'Claude'}\n`);
|
|
4839
|
+
process.stdout.write(` Model: ${settings.headModel || policy.model} (${settings.effort || policy.effort || 'default'})\n`);
|
|
4840
|
+
process.stdout.write(' Mode: Smart Auto\n');
|
|
4841
|
+
process.stdout.write(` Permissions: ${provider === 'codex' ? 'never ask + Replit sandbox boundary' : 'auto'}\n\n`);
|
|
4842
|
+
process.stdout.write(' Enter start recommended p start with pasted prompt b back\n\n');
|
|
4843
|
+
};
|
|
4844
|
+
|
|
4845
|
+
renderStart();
|
|
4846
|
+
let choice = (await ask(' Choice: ')).trim().toLowerCase();
|
|
4847
|
+
let initialPrompt = '';
|
|
4848
|
+
if (choice === 'b' || choice === 'q') return { next: 'main' };
|
|
4849
|
+
if (choice === 'p' || choice === 'prompt') {
|
|
4850
|
+
initialPrompt = (await ask(' Initial prompt: ')).trim();
|
|
4851
|
+
}
|
|
4852
|
+
|
|
4853
|
+
const policy = _headPolicyFor(provider, profile, settings);
|
|
4854
|
+
if (!_modelMatchesProvider(settings.headModel, provider)) settings.headModel = policy.model;
|
|
4855
|
+
if (!settings.effort) settings.effort = policy.effort;
|
|
4856
|
+
settings.automode = true;
|
|
4857
|
+
settings.bypassPermissions = false;
|
|
4858
|
+
saveSessionSettings(cwd, settings);
|
|
4859
|
+
|
|
4860
|
+
const session = {
|
|
4861
|
+
id: randomUUID(),
|
|
4862
|
+
tool: provider,
|
|
4863
|
+
smartName: 'New HEAD Conversation',
|
|
4864
|
+
firstPrompt: initialPrompt || 'New dual-brain HEAD conversation',
|
|
4865
|
+
};
|
|
4866
|
+
const launchArgs = provider === 'codex'
|
|
4867
|
+
? _codexNewArgs(cwd)
|
|
4868
|
+
: ['--session-id', session.id, ..._claudeNewArgs(cwd)];
|
|
4869
|
+
if (initialPrompt) launchArgs.push(initialPrompt);
|
|
4870
|
+
|
|
4871
|
+
process.stdout.write('\n');
|
|
4872
|
+
process.stdout.write(' Starting HEAD in Smart Auto...\n');
|
|
4873
|
+
process.stdout.write(` Provider: ${provider === 'codex' ? 'GPT/Codex' : 'Claude'}\n`);
|
|
4874
|
+
process.stdout.write(` Model: ${settings.headModel || 'default'}${settings.effort ? ` (${settings.effort})` : ''}\n`);
|
|
4875
|
+
process.stdout.write(` Launch: ${provider} ${launchArgs.join(' ')}\n\n`);
|
|
4876
|
+
|
|
4877
|
+
writeActiveConversation(cwd, session, provider, {
|
|
4878
|
+
model: settings.headModel || null,
|
|
4879
|
+
effort: settings.effort || null,
|
|
4880
|
+
automode: true,
|
|
4881
|
+
bypassPermissions: false,
|
|
4882
|
+
});
|
|
4883
|
+
try {
|
|
4884
|
+
await launchSupervisedHead(provider, launchArgs, cwd, session);
|
|
4885
|
+
} finally {
|
|
4886
|
+
clearActiveConversation(cwd, session.id);
|
|
4887
|
+
}
|
|
4788
4888
|
|
|
4789
4889
|
return { next: 'main' };
|
|
4790
4890
|
}
|
package/package.json
CHANGED