helixmind 0.6.0 → 0.6.2
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/dist/cli/agent/turn-directives.d.ts +12 -0
- package/dist/cli/agent/turn-directives.d.ts.map +1 -0
- package/dist/cli/agent/turn-directives.js +89 -0
- package/dist/cli/agent/turn-directives.js.map +1 -0
- package/dist/cli/auth/feature-gate.js +4 -4
- package/dist/cli/auth/feature-gate.js.map +1 -1
- package/dist/cli/auth/guard.js +2 -2
- package/dist/cli/auth/guard.js.map +1 -1
- package/dist/cli/brain/generator.d.ts.map +1 -1
- package/dist/cli/brain/generator.js +44 -1
- package/dist/cli/brain/generator.js.map +1 -1
- package/dist/cli/commands/chat.d.ts.map +1 -1
- package/dist/cli/commands/chat.js +312 -143
- package/dist/cli/commands/chat.js.map +1 -1
- package/dist/cli/jarvis/daemon.js +1 -1
- package/dist/cli/jarvis/daemon.js.map +1 -1
- package/dist/cli/jarvis/identity.d.ts +1 -1
- package/dist/cli/jarvis/identity.js +6 -6
- package/dist/cli/jarvis/onboarding.js +1 -1
- package/dist/cli/jarvis/onboarding.js.map +1 -1
- package/dist/cli/jarvis/orchestrator.d.ts +13 -0
- package/dist/cli/jarvis/orchestrator.d.ts.map +1 -1
- package/dist/cli/jarvis/orchestrator.js +102 -26
- package/dist/cli/jarvis/orchestrator.js.map +1 -1
- package/dist/cli/ui/activity.d.ts.map +1 -1
- package/dist/cli/ui/activity.js +12 -1
- package/dist/cli/ui/activity.js.map +1 -1
- package/dist/cli/ui/command-suggest.d.ts.map +1 -1
- package/dist/cli/ui/command-suggest.js +2 -0
- package/dist/cli/ui/command-suggest.js.map +1 -1
- package/dist/cli/validation/policy.d.ts +13 -0
- package/dist/cli/validation/policy.d.ts.map +1 -0
- package/dist/cli/validation/policy.js +34 -0
- package/dist/cli/validation/policy.js.map +1 -0
- package/package.json +1 -1
|
@@ -21,6 +21,7 @@ import { showHelixMenu } from './helix-menu.js';
|
|
|
21
21
|
import { initializeTools } from '../agent/tools/registry.js';
|
|
22
22
|
import { runAgentLoop, AgentController, AgentAbortError } from '../agent/loop.js';
|
|
23
23
|
import { PermissionManager } from '../agent/permissions.js';
|
|
24
|
+
import { parseTurnDirectives } from '../agent/turn-directives.js';
|
|
24
25
|
import { UndoStack } from '../agent/undo.js';
|
|
25
26
|
import { renderStatusBar, getGitInfo } from '../ui/statusbar.js';
|
|
26
27
|
import { CheckpointStore } from '../checkpoints/store.js';
|
|
@@ -60,6 +61,7 @@ import { classifyTask } from '../validation/classifier.js';
|
|
|
60
61
|
import { generateCriteria } from '../validation/criteria.js';
|
|
61
62
|
import { validationLoop } from '../validation/autofix.js';
|
|
62
63
|
import { createValidationProvider } from '../validation/model.js';
|
|
64
|
+
import { resolveValidationDecision } from '../validation/policy.js';
|
|
63
65
|
import { renderValidationSummary, renderValidationStart, renderClassification } from '../validation/reporter.js';
|
|
64
66
|
import { storeValidationResult, getValidationStats, renderValidationStats } from '../validation/stats.js';
|
|
65
67
|
import { isFeatureAvailable, getJarvisLimitsForPlan, getBrainLimitsForPlan, isLoggedIn } from '../auth/feature-gate.js';
|
|
@@ -80,6 +82,8 @@ const HELP_CATEGORIES = [
|
|
|
80
82
|
{ cmd: '/clear', label: '/clear', description: 'Clear conversation history' },
|
|
81
83
|
{ cmd: '/model', label: '/model', description: 'Switch LLM model' },
|
|
82
84
|
{ cmd: '/keys', label: '/keys', description: 'Manage API keys' },
|
|
85
|
+
{ cmd: '/fast [prompt]', label: '/fast', description: 'Low-latency turn (skip validation, no auto-swarm)' },
|
|
86
|
+
{ cmd: '/swarm [prompt]', label: '/swarm', description: 'Force swarm decomposition for one turn' },
|
|
83
87
|
{ cmd: '/yolo', label: '/yolo', description: 'Toggle YOLO mode' },
|
|
84
88
|
{ cmd: '/skip-permissions', label: '/skip-permissions', description: 'Toggle skip-permissions' },
|
|
85
89
|
{ cmd: '/plan', label: '/plan', description: 'Toggle plan mode (read-only → plan → execute)' },
|
|
@@ -225,10 +229,12 @@ const HELP_TEXT = `
|
|
|
225
229
|
${chalk.hex('#00d4ff').bold(' Chat & Interaction')}
|
|
226
230
|
${theme.primary('/help'.padEnd(22))} ${theme.dim('Show this help')}
|
|
227
231
|
${theme.primary('/clear'.padEnd(22))} ${theme.dim('Clear conversation history')}
|
|
228
|
-
${theme.primary('/model [name]'.padEnd(22))} ${theme.dim('Switch model (interactive or direct: /model gpt-4o)')}
|
|
229
|
-
${theme.primary('/keys'.padEnd(22))} ${theme.dim('Add/remove/update API keys')}
|
|
230
|
-
${theme.primary('/
|
|
231
|
-
${theme.primary('/
|
|
232
|
+
${theme.primary('/model [name]'.padEnd(22))} ${theme.dim('Switch model (interactive or direct: /model gpt-4o)')}
|
|
233
|
+
${theme.primary('/keys'.padEnd(22))} ${theme.dim('Add/remove/update API keys')}
|
|
234
|
+
${theme.primary('/fast [prompt]'.padEnd(22))} ${theme.dim('One fast turn: skip validation and auto-swarm')}
|
|
235
|
+
${theme.primary('/swarm [prompt]'.padEnd(22))} ${theme.dim('Force multi-agent swarm for one request')}
|
|
236
|
+
${theme.primary('/yolo [on|off]'.padEnd(22))} ${theme.dim('Toggle YOLO mode — auto-approve ALL operations')}
|
|
237
|
+
${theme.primary('/skip-permissions'.padEnd(22))} ${theme.dim('Toggle skip-permissions (auto-approve safe ops)')}
|
|
232
238
|
|
|
233
239
|
${chalk.hex('#00ff88').bold(' Spiral Memory')}
|
|
234
240
|
${theme.primary('/spiral'.padEnd(22))} ${theme.dim('Show spiral status (nodes per level)')}
|
|
@@ -411,11 +417,13 @@ export async function chatCommand(options) {
|
|
|
411
417
|
let jarvisTelegramBot = null;
|
|
412
418
|
let jarvisLearning;
|
|
413
419
|
let jarvisScope;
|
|
420
|
+
let jarvisRuntimeReady = false;
|
|
421
|
+
let pendingJarvisQueueBinder = null;
|
|
414
422
|
let jarvisDaemonSession = null;
|
|
415
423
|
let jarvisPaused = false;
|
|
416
424
|
const resolveJarvisRoot = (scope) => scope === 'project' ? process.cwd() : join(homedir(), '.spiral-context');
|
|
417
|
-
// Browser controller
|
|
418
|
-
let browserController
|
|
425
|
+
// Browser controller stays lazy so plain chat startup avoids browser setup work.
|
|
426
|
+
let browserController;
|
|
419
427
|
let visionProcessor;
|
|
420
428
|
// Terminal + Screen (replaces BottomChrome with framed input area)
|
|
421
429
|
const terminal = new Terminal();
|
|
@@ -428,6 +436,16 @@ export async function chatCommand(options) {
|
|
|
428
436
|
const chrome = screen;
|
|
429
437
|
// Activity indicator (renders on chrome row 0 during agent work)
|
|
430
438
|
const activity = new ActivityIndicator(chrome);
|
|
439
|
+
const chromeRowCache = new Map();
|
|
440
|
+
function invalidateChromeRows() {
|
|
441
|
+
chromeRowCache.clear();
|
|
442
|
+
}
|
|
443
|
+
function setChromeRow(row, content, force = false) {
|
|
444
|
+
if (!force && chromeRowCache.get(row) === content)
|
|
445
|
+
return;
|
|
446
|
+
chromeRowCache.set(row, content);
|
|
447
|
+
chrome.setRow(row, content);
|
|
448
|
+
}
|
|
431
449
|
// Agent controller for pause/resume
|
|
432
450
|
const agentController = new AgentController();
|
|
433
451
|
let agentRunning = false;
|
|
@@ -557,28 +575,53 @@ export async function chatCommand(options) {
|
|
|
557
575
|
}
|
|
558
576
|
// Jarvis scope follows brain scope — init after brainScope detection
|
|
559
577
|
jarvisScope = brainScope;
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
578
|
+
function initializeJarvisRuntime(scope = jarvisScope) {
|
|
579
|
+
const root = resolveJarvisRoot(scope);
|
|
580
|
+
jarvisScope = scope;
|
|
581
|
+
jarvisQueue = new JarvisQueue(root);
|
|
582
|
+
jarvisIdentity = new JarvisIdentityManager(root);
|
|
583
|
+
jarvisProposals = new ProposalJournal(root);
|
|
584
|
+
jarvisScheduler = new JarvisScheduler(root);
|
|
585
|
+
jarvisTriggers = new TriggerManager(root);
|
|
586
|
+
jarvisWorldModel = new WorldModelManager(root);
|
|
587
|
+
jarvisAutonomy = new AutonomyManager(jarvisIdentity.getIdentity().autonomyLevel);
|
|
588
|
+
jarvisNotifications = new NotificationManager(root);
|
|
589
|
+
jarvisSkills = new SkillManager(root);
|
|
590
|
+
jarvisSkills.syncRegistry();
|
|
591
|
+
jarvisLearning = new LearningJournal(root);
|
|
592
|
+
jarvisSentiment = new SentimentAnalyzer(root, {
|
|
593
|
+
onShift: (from, to, frustrationLevel) => {
|
|
594
|
+
jarvisIdentity.recordEvent({ type: 'sentiment_shift', from, to, frustrationLevel });
|
|
595
|
+
import('../brain/generator.js').then(mod => {
|
|
596
|
+
if (mod.isBrainServerRunning?.()) {
|
|
597
|
+
mod.pushNeuronFired?.('yellow', '#ff6b6b', 'sentiment');
|
|
598
|
+
}
|
|
599
|
+
}).catch(() => { });
|
|
600
|
+
},
|
|
601
|
+
});
|
|
602
|
+
jarvisRuntimeReady = true;
|
|
603
|
+
pendingJarvisQueueBinder?.();
|
|
604
|
+
}
|
|
605
|
+
function ensureJarvisRuntime(scope = jarvisScope) {
|
|
606
|
+
if (jarvisRuntimeReady && jarvisScope === scope)
|
|
607
|
+
return;
|
|
608
|
+
initializeJarvisRuntime(scope);
|
|
609
|
+
}
|
|
610
|
+
function warmJarvisRuntime(scope = jarvisScope) {
|
|
611
|
+
if (jarvisRuntimeReady && jarvisScope === scope)
|
|
612
|
+
return;
|
|
613
|
+
setTimeout(() => {
|
|
614
|
+
try {
|
|
615
|
+
ensureJarvisRuntime(scope);
|
|
616
|
+
}
|
|
617
|
+
catch {
|
|
618
|
+
// Best effort: Jarvis can still initialize on first real use.
|
|
619
|
+
}
|
|
620
|
+
}, 0);
|
|
621
|
+
}
|
|
581
622
|
let spiralEngine = null;
|
|
623
|
+
let spiralInitPromise = null;
|
|
624
|
+
let spiralInitScope = null;
|
|
582
625
|
async function initSpiralEngine(scope) {
|
|
583
626
|
try {
|
|
584
627
|
const { SpiralEngine } = await import('../../spiral/engine.js');
|
|
@@ -593,8 +636,58 @@ export async function chatCommand(options) {
|
|
|
593
636
|
return null;
|
|
594
637
|
}
|
|
595
638
|
}
|
|
596
|
-
|
|
597
|
-
|
|
639
|
+
async function ensureSpiralEngine(scope = brainScope) {
|
|
640
|
+
if (!config.spiral.enabled)
|
|
641
|
+
return null;
|
|
642
|
+
if (spiralEngine && spiralInitScope === scope)
|
|
643
|
+
return spiralEngine;
|
|
644
|
+
if (spiralInitPromise && spiralInitScope === scope)
|
|
645
|
+
return spiralInitPromise;
|
|
646
|
+
spiralInitScope = scope;
|
|
647
|
+
spiralInitPromise = initSpiralEngine(scope).then(async (engine) => {
|
|
648
|
+
spiralEngine = engine;
|
|
649
|
+
spiralInitPromise = null;
|
|
650
|
+
if (engine && brainUrl) {
|
|
651
|
+
try {
|
|
652
|
+
const { startLiveBrain } = await import('../brain/generator.js');
|
|
653
|
+
await startLiveBrain(engine, project.name || 'HelixMind', scope);
|
|
654
|
+
}
|
|
655
|
+
catch {
|
|
656
|
+
// Dashboard sync is best effort.
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
return engine;
|
|
660
|
+
}).catch((err) => {
|
|
661
|
+
spiralInitPromise = null;
|
|
662
|
+
spiralInitScope = null;
|
|
663
|
+
throw err;
|
|
664
|
+
});
|
|
665
|
+
return spiralInitPromise;
|
|
666
|
+
}
|
|
667
|
+
async function getSpiralEngine(scope = brainScope) {
|
|
668
|
+
if (!config.spiral.enabled)
|
|
669
|
+
return null;
|
|
670
|
+
if (spiralEngine && spiralInitScope === scope)
|
|
671
|
+
return spiralEngine;
|
|
672
|
+
const engine = await ensureSpiralEngine(scope);
|
|
673
|
+
spiralEngine = engine;
|
|
674
|
+
return engine;
|
|
675
|
+
}
|
|
676
|
+
function warmSpiralEngine(scope = brainScope) {
|
|
677
|
+
if (!config.spiral.enabled)
|
|
678
|
+
return;
|
|
679
|
+
void ensureSpiralEngine(scope).catch(() => { });
|
|
680
|
+
}
|
|
681
|
+
function resetSpiralEngine(scope) {
|
|
682
|
+
if (spiralEngine) {
|
|
683
|
+
try {
|
|
684
|
+
spiralEngine.close();
|
|
685
|
+
}
|
|
686
|
+
catch { /* best effort */ }
|
|
687
|
+
}
|
|
688
|
+
spiralEngine = null;
|
|
689
|
+
spiralInitPromise = null;
|
|
690
|
+
spiralInitScope = scope ?? null;
|
|
598
691
|
}
|
|
599
692
|
// Register current brain in manager (so limits track it)
|
|
600
693
|
if (brainManager) {
|
|
@@ -617,6 +710,7 @@ export async function chatCommand(options) {
|
|
|
617
710
|
}
|
|
618
711
|
// Build SkillContext for skill activation
|
|
619
712
|
function buildSkillContext() {
|
|
713
|
+
ensureJarvisRuntime();
|
|
620
714
|
return {
|
|
621
715
|
registerTool: (name, def, handler) => {
|
|
622
716
|
// Skills register tools into the skill manager's registry
|
|
@@ -626,10 +720,11 @@ export async function chatCommand(options) {
|
|
|
626
720
|
unregisterTool: (_name) => { },
|
|
627
721
|
addTask: (title, desc, priority) => jarvisQueue.addTask(title, desc, { priority }),
|
|
628
722
|
querySpiral: async (query) => {
|
|
629
|
-
|
|
723
|
+
const engine = spiralEngine ?? await ensureSpiralEngine(brainScope);
|
|
724
|
+
if (!engine)
|
|
630
725
|
return '';
|
|
631
726
|
try {
|
|
632
|
-
const results = await
|
|
727
|
+
const results = await engine.query(query, { maxResults: 10 });
|
|
633
728
|
return results.level_1.concat(results.level_2, results.level_3)
|
|
634
729
|
.map((n) => `[${n.type}] ${n.content}`)
|
|
635
730
|
.join('\n')
|
|
@@ -640,10 +735,11 @@ export async function chatCommand(options) {
|
|
|
640
735
|
}
|
|
641
736
|
},
|
|
642
737
|
storeInSpiral: async (content, type, tags) => {
|
|
643
|
-
|
|
738
|
+
const engine = spiralEngine ?? await ensureSpiralEngine(brainScope);
|
|
739
|
+
if (!engine)
|
|
644
740
|
return;
|
|
645
741
|
try {
|
|
646
|
-
await
|
|
742
|
+
await engine.add(content, { type, tags });
|
|
647
743
|
}
|
|
648
744
|
catch { }
|
|
649
745
|
},
|
|
@@ -657,6 +753,7 @@ export async function chatCommand(options) {
|
|
|
657
753
|
}
|
|
658
754
|
// Start Telegram bot if configured (called when daemon starts)
|
|
659
755
|
function startTelegramBot() {
|
|
756
|
+
ensureJarvisRuntime();
|
|
660
757
|
if (jarvisTelegramBot?.isRunning)
|
|
661
758
|
return;
|
|
662
759
|
const teleConfig = jarvisNotifications.getConfig().targets.find(t => t.channel === 'telegram');
|
|
@@ -777,6 +874,7 @@ export async function chatCommand(options) {
|
|
|
777
874
|
}
|
|
778
875
|
// Build ThinkingCallbacks for Jarvis AGI thinking loop
|
|
779
876
|
function buildThinkingCallbacks(bgSession) {
|
|
877
|
+
ensureJarvisRuntime();
|
|
780
878
|
return {
|
|
781
879
|
sendMessage: async (prompt) => {
|
|
782
880
|
bgSession.controller.reset();
|
|
@@ -789,10 +887,11 @@ export async function chatCommand(options) {
|
|
|
789
887
|
isAborted: () => bgSession.controller.isAborted,
|
|
790
888
|
isPaused: () => jarvisPaused,
|
|
791
889
|
querySpiral: async (query, maxTokens) => {
|
|
792
|
-
|
|
890
|
+
const engine = spiralEngine ?? await ensureSpiralEngine(brainScope);
|
|
891
|
+
if (!engine)
|
|
793
892
|
return '';
|
|
794
893
|
try {
|
|
795
|
-
const results = await
|
|
894
|
+
const results = await engine.query(query, { maxResults: maxTokens ?? 50 });
|
|
796
895
|
return results.level_1.concat(results.level_2, results.level_3)
|
|
797
896
|
.map((n) => `[${n.type}] ${n.content}`)
|
|
798
897
|
.join('\n')
|
|
@@ -803,10 +902,11 @@ export async function chatCommand(options) {
|
|
|
803
902
|
}
|
|
804
903
|
},
|
|
805
904
|
storeInSpiral: async (content, type, tags) => {
|
|
806
|
-
|
|
905
|
+
const engine = spiralEngine ?? await ensureSpiralEngine(brainScope);
|
|
906
|
+
if (!engine)
|
|
807
907
|
return;
|
|
808
908
|
try {
|
|
809
|
-
await
|
|
909
|
+
await engine.add(content, { type: type, tags });
|
|
810
910
|
}
|
|
811
911
|
catch { }
|
|
812
912
|
},
|
|
@@ -1210,7 +1310,8 @@ export async function chatCommand(options) {
|
|
|
1210
1310
|
bgSession.controller.reset();
|
|
1211
1311
|
const rth = { text: '' };
|
|
1212
1312
|
bgSession.buffer.onSummary = (t) => { rth.text = t; };
|
|
1213
|
-
|
|
1313
|
+
const activeSpiral = await getSpiralEngine(brainScope);
|
|
1314
|
+
await sendAgentMessage(prompt, bgSession.history, provider, project, activeSpiral, config, permissions, bgSession.undoStack, checkpointStore, bgSession.controller, new ActivityIndicator(), bgSession.buffer, (inp, out) => { sessionTokensInput += inp; sessionTokensOutput += out; }, () => { sessionToolCalls++; }, undefined, { enabled: false, verbose: false, strict: false });
|
|
1214
1315
|
bgSession.buffer.onSummary = undefined;
|
|
1215
1316
|
return rth.text;
|
|
1216
1317
|
},
|
|
@@ -1306,6 +1407,7 @@ export async function chatCommand(options) {
|
|
|
1306
1407
|
return bugJournal.delete(id);
|
|
1307
1408
|
},
|
|
1308
1409
|
startJarvis: () => {
|
|
1410
|
+
ensureJarvisRuntime();
|
|
1309
1411
|
if (jarvisDaemonSession && jarvisDaemonSession.status === 'running')
|
|
1310
1412
|
return jarvisDaemonSession.id;
|
|
1311
1413
|
// Enforce cross-process Jarvis instance limit
|
|
@@ -1362,9 +1464,12 @@ export async function chatCommand(options) {
|
|
|
1362
1464
|
pushSessionUpdate(serializeSession(bgSession));
|
|
1363
1465
|
},
|
|
1364
1466
|
updateStatus: () => updateStatusBar(),
|
|
1365
|
-
storeInSpiral:
|
|
1467
|
+
storeInSpiral: config.spiral.enabled ? async (content, type, tags) => {
|
|
1468
|
+
const activeSpiral = await getSpiralEngine(brainScope);
|
|
1469
|
+
if (!activeSpiral)
|
|
1470
|
+
return;
|
|
1366
1471
|
try {
|
|
1367
|
-
await
|
|
1472
|
+
await activeSpiral.add(content, { type: type, tags });
|
|
1368
1473
|
}
|
|
1369
1474
|
catch { }
|
|
1370
1475
|
} : undefined,
|
|
@@ -1398,6 +1503,7 @@ export async function chatCommand(options) {
|
|
|
1398
1503
|
return true;
|
|
1399
1504
|
},
|
|
1400
1505
|
pauseJarvis: () => {
|
|
1506
|
+
ensureJarvisRuntime();
|
|
1401
1507
|
if (!jarvisDaemonSession || jarvisPaused)
|
|
1402
1508
|
return false;
|
|
1403
1509
|
jarvisPaused = true;
|
|
@@ -1405,6 +1511,7 @@ export async function chatCommand(options) {
|
|
|
1405
1511
|
return true;
|
|
1406
1512
|
},
|
|
1407
1513
|
resumeJarvis: () => {
|
|
1514
|
+
ensureJarvisRuntime();
|
|
1408
1515
|
if (!jarvisDaemonSession || !jarvisPaused)
|
|
1409
1516
|
return false;
|
|
1410
1517
|
jarvisPaused = false;
|
|
@@ -1412,24 +1519,36 @@ export async function chatCommand(options) {
|
|
|
1412
1519
|
return true;
|
|
1413
1520
|
},
|
|
1414
1521
|
addJarvisTask: (title, description, opts) => {
|
|
1522
|
+
ensureJarvisRuntime();
|
|
1415
1523
|
const task = jarvisQueue.addTask(title, description, opts);
|
|
1416
1524
|
return serializeJarvisTask(task);
|
|
1417
1525
|
},
|
|
1418
|
-
listJarvisTasks: () =>
|
|
1526
|
+
listJarvisTasks: () => {
|
|
1527
|
+
ensureJarvisRuntime();
|
|
1528
|
+
return jarvisQueue.getAllTasks().map(serializeJarvisTask);
|
|
1529
|
+
},
|
|
1419
1530
|
deleteJarvisTask: (taskId) => {
|
|
1531
|
+
ensureJarvisRuntime();
|
|
1420
1532
|
return jarvisQueue.removeTask(taskId);
|
|
1421
1533
|
},
|
|
1422
|
-
getJarvisStatus: () =>
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1534
|
+
getJarvisStatus: () => {
|
|
1535
|
+
ensureJarvisRuntime();
|
|
1536
|
+
return {
|
|
1537
|
+
...jarvisQueue.getStatus(),
|
|
1538
|
+
scope: jarvisScope === 'project' ? 'local' : 'global',
|
|
1539
|
+
jarvisName: jarvisIdentity.getIdentity().name,
|
|
1540
|
+
};
|
|
1541
|
+
},
|
|
1542
|
+
clearJarvisCompleted: () => {
|
|
1543
|
+
ensureJarvisRuntime();
|
|
1544
|
+
return jarvisQueue.clearCompleted();
|
|
1545
|
+
},
|
|
1428
1546
|
// Jarvis AGI handlers (stubs — wired when AGI modules are initialized)
|
|
1429
1547
|
listProposals: () => [],
|
|
1430
1548
|
approveProposal: () => false,
|
|
1431
1549
|
denyProposal: () => false,
|
|
1432
1550
|
setAutonomyLevel: (level) => {
|
|
1551
|
+
ensureJarvisRuntime();
|
|
1433
1552
|
if (level < 0 || level > 5)
|
|
1434
1553
|
return false;
|
|
1435
1554
|
jarvisAutonomy.setLevel(level);
|
|
@@ -1776,19 +1895,24 @@ export async function chatCommand(options) {
|
|
|
1776
1895
|
pushBugUpdated(bugInfo);
|
|
1777
1896
|
}
|
|
1778
1897
|
});
|
|
1779
|
-
// Wire Jarvis queue change events to brain server
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1898
|
+
// Wire Jarvis queue change events to brain server when Jarvis runtime exists.
|
|
1899
|
+
pendingJarvisQueueBinder = () => {
|
|
1900
|
+
if (!jarvisRuntimeReady)
|
|
1901
|
+
return;
|
|
1902
|
+
jarvisQueue.setOnChange((event, task) => {
|
|
1903
|
+
const info = serializeJarvisTask(task);
|
|
1904
|
+
if (event === 'task_created') {
|
|
1905
|
+
pushJarvisTaskCreated(info);
|
|
1906
|
+
}
|
|
1907
|
+
else if (event === 'task_removed') {
|
|
1908
|
+
pushJarvisTaskRemoved(task.id);
|
|
1909
|
+
}
|
|
1910
|
+
else {
|
|
1911
|
+
pushJarvisTaskUpdated(info);
|
|
1912
|
+
}
|
|
1913
|
+
});
|
|
1914
|
+
};
|
|
1915
|
+
pendingJarvisQueueBinder();
|
|
1792
1916
|
// Wire browser screenshots to brain server
|
|
1793
1917
|
pushScreenshotToBrainFn = (info) => {
|
|
1794
1918
|
pushBrowserScreenshot({
|
|
@@ -1888,6 +2012,34 @@ export async function chatCommand(options) {
|
|
|
1888
2012
|
hints.push(chalk.dim('esc to interrupt'));
|
|
1889
2013
|
return hints.join(chalk.dim(' \u00B7 '));
|
|
1890
2014
|
}
|
|
2015
|
+
function renderExecutionIntent(directives, validationDecision, swarmHeuristic, usingSwarm) {
|
|
2016
|
+
const parts = [];
|
|
2017
|
+
if (usingSwarm) {
|
|
2018
|
+
const reason = swarmHeuristic.reasons.slice(0, 2).join(', ');
|
|
2019
|
+
parts.push(chalk.hex('#ffd700')('swarm'));
|
|
2020
|
+
if (reason)
|
|
2021
|
+
parts.push(chalk.dim(reason));
|
|
2022
|
+
}
|
|
2023
|
+
else {
|
|
2024
|
+
parts.push(chalk.hex('#00d4ff')('single-agent'));
|
|
2025
|
+
if (directives.skipSwarm) {
|
|
2026
|
+
parts.push(chalk.dim('swarm skipped'));
|
|
2027
|
+
}
|
|
2028
|
+
else if (swarmHeuristic.shouldOrchestrate) {
|
|
2029
|
+
parts.push(chalk.dim('swarm available but not used'));
|
|
2030
|
+
}
|
|
2031
|
+
}
|
|
2032
|
+
if (validationDecision.enabled) {
|
|
2033
|
+
parts.push(chalk.green('validation on'));
|
|
2034
|
+
}
|
|
2035
|
+
else {
|
|
2036
|
+
parts.push(chalk.yellow(`validation off (${validationDecision.reason})`));
|
|
2037
|
+
}
|
|
2038
|
+
if (directives.fastMode) {
|
|
2039
|
+
parts.push(chalk.hex('#ff6600')('fast lane'));
|
|
2040
|
+
}
|
|
2041
|
+
renderInfo(chalk.dim('Intent: ') + parts.join(chalk.dim(' · ')));
|
|
2042
|
+
}
|
|
1891
2043
|
/**
|
|
1892
2044
|
* Show the full prompt area using sticky bottom chrome (4 rows):
|
|
1893
2045
|
* ┌──────────────────────────────────────┐ ← chrome row 0 (N-3): top border / activity indicator
|
|
@@ -1912,9 +2064,9 @@ export async function chatCommand(options) {
|
|
|
1912
2064
|
}
|
|
1913
2065
|
// Now set chrome content and draw (screen must be active for these to render)
|
|
1914
2066
|
screen.drawFrameBottom();
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
2067
|
+
setChromeRow(1, hintLine, true);
|
|
2068
|
+
setChromeRow(2, ' ' + statusLine1, true);
|
|
2069
|
+
setChromeRow(3, ' ' + statusLine2, true);
|
|
1918
2070
|
isAtPrompt = true;
|
|
1919
2071
|
// Suppress stdout hook redraws while InputManager manages the cursor
|
|
1920
2072
|
screen.inputActive = true;
|
|
@@ -2008,6 +2160,7 @@ export async function chatCommand(options) {
|
|
|
2008
2160
|
// Update screen and activity on terminal resize
|
|
2009
2161
|
process.stdout.on('resize', () => {
|
|
2010
2162
|
closeSuggestionPanel(); // Close panel on resize (reopens on next keypress)
|
|
2163
|
+
invalidateChromeRows();
|
|
2011
2164
|
screen.handleResize();
|
|
2012
2165
|
activity.handleResize();
|
|
2013
2166
|
if (isAtPrompt) {
|
|
@@ -2039,9 +2192,11 @@ export async function chatCommand(options) {
|
|
|
2039
2192
|
isAtPrompt = active;
|
|
2040
2193
|
// Deactivate/activate bottom chrome so permission select menu renders cleanly
|
|
2041
2194
|
if (active) {
|
|
2195
|
+
invalidateChromeRows();
|
|
2042
2196
|
chrome.deactivate();
|
|
2043
2197
|
}
|
|
2044
2198
|
else {
|
|
2199
|
+
invalidateChromeRows();
|
|
2045
2200
|
chrome.activate();
|
|
2046
2201
|
}
|
|
2047
2202
|
});
|
|
@@ -2065,7 +2220,7 @@ export async function chatCommand(options) {
|
|
|
2065
2220
|
if (isAtPrompt) {
|
|
2066
2221
|
const hintLine = buildHintLine();
|
|
2067
2222
|
activity.setRestoreContent(hintLine);
|
|
2068
|
-
|
|
2223
|
+
invalidateChromeRows();
|
|
2069
2224
|
updateStatusBar();
|
|
2070
2225
|
}
|
|
2071
2226
|
});
|
|
@@ -2234,12 +2389,7 @@ export async function chatCommand(options) {
|
|
|
2234
2389
|
if (newScope === brainScope)
|
|
2235
2390
|
return;
|
|
2236
2391
|
try {
|
|
2237
|
-
|
|
2238
|
-
try {
|
|
2239
|
-
spiralEngine.close();
|
|
2240
|
-
}
|
|
2241
|
-
catch { /* best effort */ }
|
|
2242
|
-
}
|
|
2392
|
+
resetSpiralEngine();
|
|
2243
2393
|
brainScope = newScope;
|
|
2244
2394
|
if (newScope === 'project') {
|
|
2245
2395
|
const { mkdirSync, existsSync } = await import('node:fs');
|
|
@@ -2258,7 +2408,7 @@ export async function chatCommand(options) {
|
|
|
2258
2408
|
}
|
|
2259
2409
|
}
|
|
2260
2410
|
}
|
|
2261
|
-
spiralEngine = await
|
|
2411
|
+
spiralEngine = await ensureSpiralEngine(newScope);
|
|
2262
2412
|
const { exportBrainData } = await import('../brain/exporter.js');
|
|
2263
2413
|
const { startLiveBrain } = await import('../brain/generator.js');
|
|
2264
2414
|
await startLiveBrain(spiralEngine, project.name || 'HelixMind', newScope);
|
|
@@ -2583,6 +2733,7 @@ export async function chatCommand(options) {
|
|
|
2583
2733
|
function getJarvisContextForPrompt() {
|
|
2584
2734
|
if (!jarvisDaemonSession || jarvisDaemonSession.status !== 'running')
|
|
2585
2735
|
return null;
|
|
2736
|
+
ensureJarvisRuntime();
|
|
2586
2737
|
const sentimentGuidance = jarvisSentiment.getResponseGuidance();
|
|
2587
2738
|
const identityPrompt = jarvisIdentity.getIdentityPrompt(jarvisSkills.getSkillsPrompt() ?? undefined, sentimentGuidance || undefined);
|
|
2588
2739
|
const runtimeContext = buildRuntimeContext({
|
|
@@ -2623,9 +2774,9 @@ export async function chatCommand(options) {
|
|
|
2623
2774
|
line1 = `${tabBar} ${statusLine1}`;
|
|
2624
2775
|
}
|
|
2625
2776
|
// Refresh hint line on row 1 (prevents stale border/status from previous layout)
|
|
2626
|
-
|
|
2627
|
-
|
|
2628
|
-
|
|
2777
|
+
setChromeRow(1, buildHintLine());
|
|
2778
|
+
setChromeRow(2, ' ' + line1);
|
|
2779
|
+
setChromeRow(3, ' ' + (statusLine2 || ''));
|
|
2629
2780
|
}
|
|
2630
2781
|
/** Push session findings to brain visualization */
|
|
2631
2782
|
function pushFindingsToBrain(session) {
|
|
@@ -2688,6 +2839,9 @@ export async function chatCommand(options) {
|
|
|
2688
2839
|
// Write the collected startup banner into the scroll region.
|
|
2689
2840
|
// Content flows bottom-up within the region, sitting just above the input frame.
|
|
2690
2841
|
screen.writeOutput(startupBannerParts.join(''));
|
|
2842
|
+
// Warm optional heavy subsystems after the prompt is already visible.
|
|
2843
|
+
warmJarvisRuntime(jarvisScope);
|
|
2844
|
+
warmSpiralEngine(brainScope);
|
|
2691
2845
|
// Footer timer — redraws statusbar on chrome rows 2+3 during agent work.
|
|
2692
2846
|
// Skipped when:
|
|
2693
2847
|
// - user is at readline prompt (isAtPrompt) — prevents cursor-jumping
|
|
@@ -2701,6 +2855,7 @@ export async function chatCommand(options) {
|
|
|
2701
2855
|
footerTimer.unref();
|
|
2702
2856
|
/** Process a complete input (single line or assembled paste block) */
|
|
2703
2857
|
async function processInput(input, displayText) {
|
|
2858
|
+
const rawInput = input;
|
|
2704
2859
|
// Clear input frame FIRST — before any renderInfo/process.stdout.write.
|
|
2705
2860
|
// This ensures the cursor moves out of the input area so all output
|
|
2706
2861
|
// (slash command results, "daemon started", etc.) goes to the scroll region.
|
|
@@ -2711,12 +2866,14 @@ export async function chatCommand(options) {
|
|
|
2711
2866
|
promptHistory.add(input, process.cwd()).catch(() => { });
|
|
2712
2867
|
// Handle /feed directly here (needs access to inlineProgressActive flag)
|
|
2713
2868
|
if (input.startsWith('/feed')) {
|
|
2714
|
-
|
|
2869
|
+
const activeSpiral = spiralEngine ?? await ensureSpiralEngine(brainScope);
|
|
2870
|
+
if (activeSpiral) {
|
|
2871
|
+
spiralEngine = activeSpiral;
|
|
2715
2872
|
const feedPath = input.split(/\s+/)[1];
|
|
2716
2873
|
const rootDir = process.cwd();
|
|
2717
2874
|
renderInfo('\u{1F300} Feeding project...\n');
|
|
2718
2875
|
try {
|
|
2719
|
-
const result = await runFeedPipeline(rootDir,
|
|
2876
|
+
const result = await runFeedPipeline(rootDir, activeSpiral, {
|
|
2720
2877
|
targetPath: feedPath,
|
|
2721
2878
|
onProgress: wrappedFeedProgress,
|
|
2722
2879
|
});
|
|
@@ -2778,8 +2935,27 @@ export async function chatCommand(options) {
|
|
|
2778
2935
|
showPrompt();
|
|
2779
2936
|
return;
|
|
2780
2937
|
}
|
|
2938
|
+
const turnDirectives = parseTurnDirectives(rawInput);
|
|
2939
|
+
input = turnDirectives.input;
|
|
2940
|
+
const renderedInput = displayText ?? turnDirectives.displayInput;
|
|
2941
|
+
if (!input) {
|
|
2942
|
+
if (turnDirectives.fastMode) {
|
|
2943
|
+
renderInfo(chalk.dim('Usage: /fast <prompt>'));
|
|
2944
|
+
}
|
|
2945
|
+
else if (turnDirectives.forceSwarm) {
|
|
2946
|
+
renderInfo(chalk.dim('Usage: /swarm <prompt>'));
|
|
2947
|
+
}
|
|
2948
|
+
else if (turnDirectives.strippedFlags.length > 0) {
|
|
2949
|
+
renderInfo(chalk.dim('Execution flags were provided without a prompt.'));
|
|
2950
|
+
}
|
|
2951
|
+
showPrompt();
|
|
2952
|
+
return;
|
|
2953
|
+
}
|
|
2781
2954
|
// Handle slash commands
|
|
2782
|
-
if (input.startsWith('/')) {
|
|
2955
|
+
if (input.startsWith('/') && !turnDirectives.forceSwarm) {
|
|
2956
|
+
if (/^\/(?:jarvis|del)\b/i.test(input)) {
|
|
2957
|
+
ensureJarvisRuntime();
|
|
2958
|
+
}
|
|
2783
2959
|
const handled = await handleSlashCommand(input, messages, agentHistory, config, spiralEngine, store, rl, permissions, undoStack, checkpointStore, sessionBuffer, { input: sessionTokensInput, output: sessionTokensOutput }, sessionToolCalls, (newProvider) => {
|
|
2784
2960
|
provider = newProvider;
|
|
2785
2961
|
config = store.getAll();
|
|
@@ -2788,12 +2964,7 @@ export async function chatCommand(options) {
|
|
|
2788
2964
|
typeAheadBuffer.length = 0;
|
|
2789
2965
|
}, async (newScope) => {
|
|
2790
2966
|
// Switch brain scope
|
|
2791
|
-
|
|
2792
|
-
try {
|
|
2793
|
-
spiralEngine.close();
|
|
2794
|
-
}
|
|
2795
|
-
catch { /* best effort */ }
|
|
2796
|
-
}
|
|
2967
|
+
resetSpiralEngine();
|
|
2797
2968
|
brainScope = newScope;
|
|
2798
2969
|
// Create .helixmind/ dir if switching to project and it doesn't exist
|
|
2799
2970
|
if (newScope === 'project') {
|
|
@@ -2817,8 +2988,8 @@ export async function chatCommand(options) {
|
|
|
2817
2988
|
}
|
|
2818
2989
|
}
|
|
2819
2990
|
}
|
|
2820
|
-
spiralEngine = await
|
|
2821
|
-
}, brainScope, async (action, goal) => {
|
|
2991
|
+
spiralEngine = await ensureSpiralEngine(newScope);
|
|
2992
|
+
}, brainScope, (scope) => getSpiralEngine(scope ?? brainScope), async (action, goal) => {
|
|
2822
2993
|
if (action === 'stop') {
|
|
2823
2994
|
// Stop all background sessions + autonomous mode
|
|
2824
2995
|
const running = sessionMgr.running;
|
|
@@ -3075,23 +3246,7 @@ export async function chatCommand(options) {
|
|
|
3075
3246
|
sentiment: jarvisSentiment,
|
|
3076
3247
|
getScope: () => jarvisScope,
|
|
3077
3248
|
setScope: (scope) => {
|
|
3078
|
-
|
|
3079
|
-
const newRoot = resolveJarvisRoot(scope);
|
|
3080
|
-
jarvisQueue = new JarvisQueue(newRoot);
|
|
3081
|
-
jarvisIdentity = new JarvisIdentityManager(newRoot);
|
|
3082
|
-
jarvisProposals = new ProposalJournal(newRoot);
|
|
3083
|
-
jarvisScheduler = new JarvisScheduler(newRoot);
|
|
3084
|
-
jarvisTriggers = new TriggerManager(newRoot);
|
|
3085
|
-
jarvisWorldModel = new WorldModelManager(newRoot);
|
|
3086
|
-
jarvisNotifications = new NotificationManager(newRoot);
|
|
3087
|
-
jarvisSkills = new SkillManager(newRoot);
|
|
3088
|
-
jarvisSkills.syncRegistry();
|
|
3089
|
-
jarvisSentiment = new SentimentAnalyzer(newRoot, {
|
|
3090
|
-
onShift: (from, to, frustrationLevel) => {
|
|
3091
|
-
jarvisIdentity.recordEvent({ type: 'sentiment_shift', from, to, frustrationLevel });
|
|
3092
|
-
},
|
|
3093
|
-
});
|
|
3094
|
-
jarvisAutonomy = new AutonomyManager(jarvisIdentity.getIdentity().autonomyLevel);
|
|
3249
|
+
initializeJarvisRuntime(scope);
|
|
3095
3250
|
},
|
|
3096
3251
|
getSession: () => jarvisDaemonSession,
|
|
3097
3252
|
setSession: (s) => { jarvisDaemonSession = s; },
|
|
@@ -3106,6 +3261,7 @@ export async function chatCommand(options) {
|
|
|
3106
3261
|
startTelegramBot,
|
|
3107
3262
|
learning: jarvisLearning,
|
|
3108
3263
|
startDaemon: () => {
|
|
3264
|
+
ensureJarvisRuntime();
|
|
3109
3265
|
const jName = jarvisIdentity.getIdentity().name;
|
|
3110
3266
|
const bgSession = sessionMgr.create(jName, '\u{1F916}', agentHistory);
|
|
3111
3267
|
bgSession.start();
|
|
@@ -3116,13 +3272,13 @@ export async function chatCommand(options) {
|
|
|
3116
3272
|
const d = chalk.dim;
|
|
3117
3273
|
const j = chalk.hex('#ff00ff');
|
|
3118
3274
|
const g = chalk.hex('#FFB800');
|
|
3119
|
-
const displayName = jName.toUpperCase()
|
|
3275
|
+
const displayName = jName.toUpperCase();
|
|
3120
3276
|
const namePad = Math.max(0, 34 - displayName.length);
|
|
3121
3277
|
const banner = '\n' +
|
|
3122
3278
|
d('\u256D' + '\u2500'.repeat(45) + '\u256E') + '\n' +
|
|
3123
3279
|
d('\u2502 ') + g('\u{1F31F}') + ' ' + j(displayName) + d(' '.repeat(namePad) + '\u2502') + '\n' +
|
|
3124
3280
|
d('\u2502' + ' '.repeat(45) + '\u2502') + '\n' +
|
|
3125
|
-
d('\u2502 ') + 'Autonomous
|
|
3281
|
+
d('\u2502 ') + 'Autonomous assistant \u2014 thinking,' + d(' \u2502') + '\n' +
|
|
3126
3282
|
d('\u2502 ') + 'proposing, executing tasks' + d(' '.repeat(17) + '\u2502') + '\n' +
|
|
3127
3283
|
d('\u2502' + ' '.repeat(45) + '\u2502') + '\n' +
|
|
3128
3284
|
d('\u2502 ') + d('/jarvis stop or ESC to stop') + d(' '.repeat(13) + '\u2502') + '\n' +
|
|
@@ -3149,7 +3305,8 @@ export async function chatCommand(options) {
|
|
|
3149
3305
|
bgSession.controller.reset();
|
|
3150
3306
|
const rth = { text: '' };
|
|
3151
3307
|
bgSession.buffer.onSummary = (t) => { rth.text = t; };
|
|
3152
|
-
|
|
3308
|
+
const activeSpiral = await getSpiralEngine(brainScope);
|
|
3309
|
+
await sendAgentMessage(prompt, bgSession.history, provider, project, activeSpiral, config, daemonPermissions, bgSession.undoStack, checkpointStore, bgSession.controller, new ActivityIndicator(), bgSession.buffer, (inp, out) => { sessionTokensInput += inp; sessionTokensOutput += out; }, () => { sessionToolCalls++; }, undefined, { enabled: false, verbose: false, strict: false });
|
|
3153
3310
|
bgSession.buffer.onSummary = undefined;
|
|
3154
3311
|
return rth.text;
|
|
3155
3312
|
},
|
|
@@ -3184,9 +3341,12 @@ export async function chatCommand(options) {
|
|
|
3184
3341
|
}
|
|
3185
3342
|
},
|
|
3186
3343
|
updateStatus: () => updateStatusBar(),
|
|
3187
|
-
storeInSpiral:
|
|
3344
|
+
storeInSpiral: config.spiral.enabled ? async (content, type, tags) => {
|
|
3345
|
+
const activeSpiral = await getSpiralEngine(brainScope);
|
|
3346
|
+
if (!activeSpiral)
|
|
3347
|
+
return;
|
|
3188
3348
|
try {
|
|
3189
|
-
await
|
|
3349
|
+
await activeSpiral.add(content, { type: type, tags });
|
|
3190
3350
|
}
|
|
3191
3351
|
catch { }
|
|
3192
3352
|
} : undefined,
|
|
@@ -3245,10 +3405,11 @@ export async function chatCommand(options) {
|
|
|
3245
3405
|
}
|
|
3246
3406
|
// Frame was already cleared at processInput entry — render user message
|
|
3247
3407
|
// Use display text (badge placeholders) if available, full text goes to model
|
|
3248
|
-
renderUserMessage(
|
|
3408
|
+
renderUserMessage(renderedInput);
|
|
3249
3409
|
// Track user message in session buffer
|
|
3250
3410
|
sessionBuffer.addUserMessage(input);
|
|
3251
3411
|
// Sentiment detection on every user message
|
|
3412
|
+
ensureJarvisRuntime();
|
|
3252
3413
|
const sentimentReading = jarvisSentiment.detectSentiment(input);
|
|
3253
3414
|
jarvisSentiment.recordReading(sentimentReading);
|
|
3254
3415
|
// Auto-detect bug reports from user messages
|
|
@@ -3401,10 +3562,16 @@ export async function chatCommand(options) {
|
|
|
3401
3562
|
}
|
|
3402
3563
|
else {
|
|
3403
3564
|
// ═══ NORMAL MODE ═══
|
|
3404
|
-
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
|
|
3565
|
+
if (config.spiral.enabled && !turnDirectives.fastMode) {
|
|
3566
|
+
spiralEngine = await ensureSpiralEngine(brainScope);
|
|
3567
|
+
}
|
|
3568
|
+
const effectiveValidation = resolveValidationDecision(input, { enabled: validationEnabled, verbose: validationVerbose, strict: validationStrict }, turnDirectives);
|
|
3569
|
+
const swarmHeuristic = swarmOrchestrator.analyze(input);
|
|
3570
|
+
const shouldUseSwarm = !activeSwarm &&
|
|
3571
|
+
!turnDirectives.skipSwarm &&
|
|
3572
|
+
(turnDirectives.forceSwarm || swarmHeuristic.shouldOrchestrate);
|
|
3573
|
+
renderExecutionIntent(turnDirectives, effectiveValidation, swarmHeuristic, shouldUseSwarm);
|
|
3574
|
+
if (shouldUseSwarm) {
|
|
3408
3575
|
const { pushSwarmCreated, pushSwarmUpdated, pushSwarmCompleted, pushWorkerStarted, pushWorkerCompleted, pushOutputLine: _pushOutputLine, pushSessionCreated: _pushSessionCreated } = await import('../brain/generator.js');
|
|
3409
3576
|
const { serializeSession: _serializeSession } = await import('../brain/control-protocol.js');
|
|
3410
3577
|
const swarm = new SwarmController(swarmOrchestrator, swarmExecutor, sessionMgr, {
|
|
@@ -3434,7 +3601,7 @@ export async function chatCommand(options) {
|
|
|
3434
3601
|
};
|
|
3435
3602
|
_pushSessionCreated(_serializeSession(session));
|
|
3436
3603
|
try {
|
|
3437
|
-
await sendAgentMessage(prompt, session.history, provider, project, spiralEngine, config, permissions, session.undoStack, checkpointStore, session.controller, bgActivity, session.buffer, (inp, out) => { sessionTokensInput += inp; sessionTokensOutput += out; }, () => { sessionToolCalls++; roundToolCalls++; }, undefined,
|
|
3604
|
+
await sendAgentMessage(prompt, session.history, provider, project, spiralEngine, config, permissions, session.undoStack, checkpointStore, session.controller, bgActivity, session.buffer, (inp, out) => { sessionTokensInput += inp; sessionTokensOutput += out; }, () => { sessionToolCalls++; roundToolCalls++; }, undefined, effectiveValidation, bugJournal, undefined, undefined, undefined, null, undefined, undefined, runtime);
|
|
3438
3605
|
}
|
|
3439
3606
|
finally {
|
|
3440
3607
|
await runtime.release();
|
|
@@ -3459,8 +3626,10 @@ export async function chatCommand(options) {
|
|
|
3459
3626
|
pushWorkerCompleted,
|
|
3460
3627
|
});
|
|
3461
3628
|
activeSwarm = swarm;
|
|
3462
|
-
|
|
3463
|
-
|
|
3629
|
+
const swarmReason = swarmHeuristic.reasons.slice(0, 2).join(', ');
|
|
3630
|
+
renderInfo(chalk.hex('#ffd700')('\u{1F41D} Swarm engaged') +
|
|
3631
|
+
(swarmReason ? chalk.dim(` — ${swarmReason}`) : ''));
|
|
3632
|
+
const summary = await swarm.run(input);
|
|
3464
3633
|
activeSwarm = null;
|
|
3465
3634
|
if (summary) {
|
|
3466
3635
|
// Swarm completed — render summary
|
|
@@ -3469,7 +3638,7 @@ export async function chatCommand(options) {
|
|
|
3469
3638
|
}
|
|
3470
3639
|
else {
|
|
3471
3640
|
// Swarm decided single task — fall through to normal agent
|
|
3472
|
-
await sendAgentMessage(input, agentHistory, provider, project, spiralEngine, config, permissions, undoStack, checkpointStore, agentController, activity, sessionBuffer, (inp, out) => { sessionTokensInput += inp; sessionTokensOutput += out; }, () => { sessionToolCalls++; roundToolCalls++; }, () => { isAtPrompt = false; },
|
|
3641
|
+
await sendAgentMessage(input, agentHistory, provider, project, spiralEngine, config, permissions, undoStack, checkpointStore, agentController, activity, sessionBuffer, (inp, out) => { sessionTokensInput += inp; sessionTokensOutput += out; }, () => { sessionToolCalls++; roundToolCalls++; }, () => { isAtPrompt = false; }, effectiveValidation, bugJournal, browserController, visionProcessor, pushScreenshotToBrainFn, getJarvisContextForPrompt(), (label, tool) => {
|
|
3473
3642
|
currentStepLabel = label;
|
|
3474
3643
|
const fileTools = new Set(['read_file', 'write_file', 'edit_file']);
|
|
3475
3644
|
currentStepFile = fileTools.has(tool) ? label.replace(/^(reading|writing|editing)\s+/, '') : '';
|
|
@@ -3488,7 +3657,7 @@ export async function chatCommand(options) {
|
|
|
3488
3657
|
// Muting is handled by activity.setMuteCallbacks (mute during LLM stream,
|
|
3489
3658
|
// unmute during tool execution so user can answer permission prompts).
|
|
3490
3659
|
isAtPrompt = false;
|
|
3491
|
-
},
|
|
3660
|
+
}, effectiveValidation, bugJournal, browserController, visionProcessor, pushScreenshotToBrainFn, getJarvisContextForPrompt(), (label, tool) => {
|
|
3492
3661
|
currentStepLabel = label;
|
|
3493
3662
|
const fileTools = new Set(['read_file', 'write_file', 'edit_file']);
|
|
3494
3663
|
currentStepFile = fileTools.has(tool) ? label.replace(/^(reading|writing|editing)\s+/, '') : '';
|
|
@@ -3503,22 +3672,7 @@ export async function chatCommand(options) {
|
|
|
3503
3672
|
while (typeAheadBuffer.length > 0 && !agentController.isAborted) {
|
|
3504
3673
|
const buffered = typeAheadBuffer.shift();
|
|
3505
3674
|
if (buffered.trim()) {
|
|
3506
|
-
|
|
3507
|
-
sessionBuffer.addUserMessage(buffered.trim());
|
|
3508
|
-
checkpointStore.createForChat(buffered.trim(), agentHistory.length);
|
|
3509
|
-
roundToolCalls = 0;
|
|
3510
|
-
currentStepLabel = '';
|
|
3511
|
-
currentStepFile = '';
|
|
3512
|
-
agentRunning = true;
|
|
3513
|
-
agentController.reset();
|
|
3514
|
-
updateStatusBar();
|
|
3515
|
-
await sendAgentMessage(buffered.trim(), agentHistory, provider, project, spiralEngine, config, permissions, undoStack, checkpointStore, agentController, activity, sessionBuffer, (inp, out) => { sessionTokensInput += inp; sessionTokensOutput += out; }, () => { sessionToolCalls++; roundToolCalls++; }, () => { showPrompt(); }, { enabled: validationEnabled, verbose: validationVerbose, strict: validationStrict }, bugJournal, browserController, visionProcessor, pushScreenshotToBrainFn, getJarvisContextForPrompt(), (label, tool) => {
|
|
3516
|
-
currentStepLabel = label;
|
|
3517
|
-
const fileTools = new Set(['read_file', 'write_file', 'edit_file']);
|
|
3518
|
-
currentStepFile = fileTools.has(tool) ? label.replace(/^(reading|writing|editing)\s+/, '') : '';
|
|
3519
|
-
});
|
|
3520
|
-
agentRunning = false;
|
|
3521
|
-
messages.push({ role: 'user', content: buffered.trim() });
|
|
3675
|
+
await processInput(buffered.trim());
|
|
3522
3676
|
}
|
|
3523
3677
|
}
|
|
3524
3678
|
showPrompt();
|
|
@@ -4008,9 +4162,15 @@ function showFullAutonomousWarning() {
|
|
|
4008
4162
|
process.stdout.write(d('\u2502 ') + d('ESC = stop agent if needed.') + d(' \u2502') + '\n');
|
|
4009
4163
|
process.stdout.write(d('\u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256F') + '\n\n');
|
|
4010
4164
|
}
|
|
4011
|
-
async function handleSlashCommand(input, messages, agentHistory, config, spiralEngine, store, rl, permissions, undoStack, checkpointStore, sessionBuffer, sessionTokens, sessionToolCalls, onProviderSwitch, onBrainSwitch, currentBrainScope, onAutonomous, onValidation, sessionManager, onRegisterBrainHandlers, onSubPrompt, bugJournal, jarvisCtx, onModeChange, chrome, planCtx, worktreeCtx) {
|
|
4165
|
+
async function handleSlashCommand(input, messages, agentHistory, config, spiralEngine, store, rl, permissions, undoStack, checkpointStore, sessionBuffer, sessionTokens, sessionToolCalls, onProviderSwitch, onBrainSwitch, currentBrainScope, resolveSpiralEngine, onAutonomous, onValidation, sessionManager, onRegisterBrainHandlers, onSubPrompt, bugJournal, jarvisCtx, onModeChange, chrome, planCtx, worktreeCtx) {
|
|
4012
4166
|
const parts = input.split(/\s+/);
|
|
4013
4167
|
let cmd = parts[0].toLowerCase();
|
|
4168
|
+
const ensureSpiralForScope = async (scope = currentBrainScope || 'global') => {
|
|
4169
|
+
if (!resolveSpiralEngine)
|
|
4170
|
+
return spiralEngine;
|
|
4171
|
+
spiralEngine = await resolveSpiralEngine(scope);
|
|
4172
|
+
return spiralEngine;
|
|
4173
|
+
};
|
|
4014
4174
|
// ─── Chrome-aware selectMenu ───────────────────────────
|
|
4015
4175
|
// Deactivates Screen during interactive menus to prevent
|
|
4016
4176
|
// stdout hook interference (menu stacking on Windows Terminal).
|
|
@@ -4112,7 +4272,7 @@ async function handleSlashCommand(input, messages, agentHistory, config, spiralE
|
|
|
4112
4272
|
rl.resume();
|
|
4113
4273
|
if (helpIdx >= 0 && helpCmds[helpIdx]) {
|
|
4114
4274
|
// Execute the selected command
|
|
4115
|
-
return handleSlashCommand(helpCmds[helpIdx], messages, agentHistory, config, spiralEngine, store, rl, permissions, undoStack, checkpointStore, sessionBuffer, sessionTokens, sessionToolCalls, onProviderSwitch, onBrainSwitch, currentBrainScope, onAutonomous, onValidation, sessionManager, onRegisterBrainHandlers, onSubPrompt, bugJournal, jarvisCtx, onModeChange, chrome, planCtx, worktreeCtx);
|
|
4275
|
+
return handleSlashCommand(helpCmds[helpIdx], messages, agentHistory, config, spiralEngine, store, rl, permissions, undoStack, checkpointStore, sessionBuffer, sessionTokens, sessionToolCalls, onProviderSwitch, onBrainSwitch, currentBrainScope, resolveSpiralEngine, onAutonomous, onValidation, sessionManager, onRegisterBrainHandlers, onSubPrompt, bugJournal, jarvisCtx, onModeChange, chrome, planCtx, worktreeCtx);
|
|
4116
4276
|
}
|
|
4117
4277
|
break;
|
|
4118
4278
|
}
|
|
@@ -4211,6 +4371,7 @@ async function handleSlashCommand(input, messages, agentHistory, config, spiralE
|
|
|
4211
4371
|
return 'drain'; // Sub-readline may leave phantom line events
|
|
4212
4372
|
}
|
|
4213
4373
|
case '/spiral':
|
|
4374
|
+
spiralEngine = await ensureSpiralForScope(currentBrainScope || 'global');
|
|
4214
4375
|
if (spiralEngine) {
|
|
4215
4376
|
try {
|
|
4216
4377
|
const status = spiralEngine.status();
|
|
@@ -4221,7 +4382,7 @@ async function handleSlashCommand(input, messages, agentHistory, config, spiralE
|
|
|
4221
4382
|
}
|
|
4222
4383
|
}
|
|
4223
4384
|
else {
|
|
4224
|
-
renderInfo('Spiral engine disabled.');
|
|
4385
|
+
renderInfo(config.spiral.enabled ? 'Spiral engine not available.' : 'Spiral engine disabled.');
|
|
4225
4386
|
}
|
|
4226
4387
|
break;
|
|
4227
4388
|
case '/helix':
|
|
@@ -4242,6 +4403,7 @@ async function handleSlashCommand(input, messages, agentHistory, config, spiralE
|
|
|
4242
4403
|
renderInfo(chalk.yellow(' Cannot use local brain here — using global'));
|
|
4243
4404
|
}
|
|
4244
4405
|
}
|
|
4406
|
+
spiralEngine = await ensureSpiralForScope('project');
|
|
4245
4407
|
// Auto-start brain visualization
|
|
4246
4408
|
if (spiralEngine) {
|
|
4247
4409
|
try {
|
|
@@ -4282,6 +4444,7 @@ async function handleSlashCommand(input, messages, agentHistory, config, spiralE
|
|
|
4282
4444
|
}
|
|
4283
4445
|
catch { /* optional */ }
|
|
4284
4446
|
}
|
|
4447
|
+
spiralEngine = await ensureSpiralForScope('global');
|
|
4285
4448
|
// Auto-start brain visualization
|
|
4286
4449
|
if (spiralEngine) {
|
|
4287
4450
|
try {
|
|
@@ -4365,6 +4528,7 @@ async function handleSlashCommand(input, messages, agentHistory, config, spiralE
|
|
|
4365
4528
|
}
|
|
4366
4529
|
// Open 3D visualization (for /brain or /brain view)
|
|
4367
4530
|
if (!brainArg || brainArg === 'view') {
|
|
4531
|
+
spiralEngine = await ensureSpiralForScope(currentBrainScope || 'global');
|
|
4368
4532
|
if (spiralEngine) {
|
|
4369
4533
|
try {
|
|
4370
4534
|
const { exportBrainData } = await import('../brain/exporter.js');
|
|
@@ -4401,6 +4565,7 @@ async function handleSlashCommand(input, messages, agentHistory, config, spiralE
|
|
|
4401
4565
|
// Handled directly in chatCommand() for access to inlineProgressActive flag
|
|
4402
4566
|
break;
|
|
4403
4567
|
case '/context':
|
|
4568
|
+
spiralEngine = await ensureSpiralForScope(currentBrainScope || 'global');
|
|
4404
4569
|
if (spiralEngine) {
|
|
4405
4570
|
const status = spiralEngine.status();
|
|
4406
4571
|
renderInfo(`Context: ${status.total_nodes} spiral nodes, ${status.total_edges} edges`);
|
|
@@ -4423,6 +4588,7 @@ async function handleSlashCommand(input, messages, agentHistory, config, spiralE
|
|
|
4423
4588
|
break;
|
|
4424
4589
|
}
|
|
4425
4590
|
case '/compact':
|
|
4591
|
+
spiralEngine = await ensureSpiralForScope(currentBrainScope || 'global');
|
|
4426
4592
|
if (spiralEngine) {
|
|
4427
4593
|
const result = spiralEngine.evolve();
|
|
4428
4594
|
renderInfo(`Evolution: ${result.promoted} promoted, ${result.demoted} demoted, ${result.summarized} summarized`);
|
|
@@ -4739,6 +4905,7 @@ async function handleSlashCommand(input, messages, agentHistory, config, spiralE
|
|
|
4739
4905
|
}
|
|
4740
4906
|
case '/export': {
|
|
4741
4907
|
const outputDir = parts[1] || process.cwd();
|
|
4908
|
+
spiralEngine = await ensureSpiralForScope(currentBrainScope || 'global');
|
|
4742
4909
|
if (spiralEngine) {
|
|
4743
4910
|
try {
|
|
4744
4911
|
const { exportToZip } = await import('../brain/archive.js');
|
|
@@ -4856,7 +5023,7 @@ async function handleSlashCommand(input, messages, agentHistory, config, spiralE
|
|
|
4856
5023
|
break;
|
|
4857
5024
|
case '/del': {
|
|
4858
5025
|
// /del task <id> — shorthand for /jarvis delete <id>
|
|
4859
|
-
if (!(await gateCheck('jarvis', 'Jarvis
|
|
5026
|
+
if (!(await gateCheck('jarvis', 'Jarvis Assistant')))
|
|
4860
5027
|
break;
|
|
4861
5028
|
if (!jarvisCtx) {
|
|
4862
5029
|
renderInfo('Jarvis not available.');
|
|
@@ -4883,7 +5050,7 @@ async function handleSlashCommand(input, messages, agentHistory, config, spiralE
|
|
|
4883
5050
|
break;
|
|
4884
5051
|
}
|
|
4885
5052
|
case '/jarvis': {
|
|
4886
|
-
if (!(await gateCheck('jarvis', 'Jarvis
|
|
5053
|
+
if (!(await gateCheck('jarvis', 'Jarvis Assistant')))
|
|
4887
5054
|
break;
|
|
4888
5055
|
if (!jarvisCtx) {
|
|
4889
5056
|
renderInfo('Jarvis not available.');
|
|
@@ -4914,7 +5081,7 @@ async function handleSlashCommand(input, messages, agentHistory, config, spiralE
|
|
|
4914
5081
|
if (!identity.customized) {
|
|
4915
5082
|
// Deactivate screen so onboarding questions render directly
|
|
4916
5083
|
// (rl.question output goes to devNull; onboarding uses process.stdout)
|
|
4917
|
-
chrome?.deactivate();
|
|
5084
|
+
chrome?.deactivate({ suspend: false });
|
|
4918
5085
|
rl.pause();
|
|
4919
5086
|
const onboardResult = await runOnboarding(jarvisCtx.identity, rl, jarvisCtx.getScope());
|
|
4920
5087
|
rl.resume();
|
|
@@ -5577,7 +5744,12 @@ async function handleSlashCommand(input, messages, agentHistory, config, spiralE
|
|
|
5577
5744
|
const port = getBrainPort();
|
|
5578
5745
|
process.stdout.write(` ${theme.success('\u{1F310} Already connected')} on port ${port}\n`);
|
|
5579
5746
|
}
|
|
5580
|
-
else
|
|
5747
|
+
else {
|
|
5748
|
+
spiralEngine = await ensureSpiralForScope(currentBrainScope || 'project');
|
|
5749
|
+
if (!spiralEngine) {
|
|
5750
|
+
renderError(config.spiral.enabled ? 'No spiral engine available.' : 'Spiral engine is disabled.');
|
|
5751
|
+
break;
|
|
5752
|
+
}
|
|
5581
5753
|
const { exportBrainData } = await import('../brain/exporter.js');
|
|
5582
5754
|
exportBrainData(spiralEngine, 'HelixMind Project', currentBrainScope || 'project');
|
|
5583
5755
|
const url = await startLiveBrain(spiralEngine, 'HelixMind Project', currentBrainScope || 'project');
|
|
@@ -5586,9 +5758,6 @@ async function handleSlashCommand(input, messages, agentHistory, config, spiralE
|
|
|
5586
5758
|
process.stdout.write(` ${theme.success('\u{1F310} Brain server started:')} ${url}\n`);
|
|
5587
5759
|
process.stdout.write(` ${theme.dim('Web dashboard can now connect.')}\n`);
|
|
5588
5760
|
}
|
|
5589
|
-
else {
|
|
5590
|
-
renderError('No spiral engine available. Run /helix first.');
|
|
5591
|
-
}
|
|
5592
5761
|
}
|
|
5593
5762
|
catch (err) {
|
|
5594
5763
|
renderError(`Failed to start brain server: ${err}`);
|