helixmind 0.7.0 → 0.7.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/commands/chat.d.ts.map +1 -1
- package/dist/cli/commands/chat.js +150 -2
- package/dist/cli/commands/chat.js.map +1 -1
- package/dist/cli/context/assembler.d.ts.map +1 -1
- package/dist/cli/context/assembler.js +29 -0
- package/dist/cli/context/assembler.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chat.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/chat.ts"],"names":[],"mappings":"AA6FA,UAAU,WAAW;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;
|
|
1
|
+
{"version":3,"file":"chat.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/chat.ts"],"names":[],"mappings":"AA6FA,UAAU,WAAW;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AA+ND,wBAAsB,WAAW,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAioIrE"}
|
|
@@ -103,6 +103,7 @@ const HELP_CATEGORIES = [
|
|
|
103
103
|
{ cmd: '/context', label: '/context', description: 'Show context size & embeddings' },
|
|
104
104
|
{ cmd: '/compact', label: '/compact', description: 'Trigger spiral evolution' },
|
|
105
105
|
{ cmd: '/tokens', label: '/tokens', description: 'Show token usage & memory' },
|
|
106
|
+
{ cmd: '/recap', label: '/recap', description: 'Toggle per-turn recap summary (on|off)' },
|
|
106
107
|
],
|
|
107
108
|
},
|
|
108
109
|
{
|
|
@@ -245,6 +246,7 @@ ${chalk.hex('#00ff88').bold(' Spiral Memory')}
|
|
|
245
246
|
${theme.primary('/context'.padEnd(22))} ${theme.dim('Show current context size & embeddings')}
|
|
246
247
|
${theme.primary('/compact'.padEnd(22))} ${theme.dim('Trigger spiral evolution (promote/demote nodes)')}
|
|
247
248
|
${theme.primary('/tokens'.padEnd(22))} ${theme.dim('Show token usage, checkpoints, memory')}
|
|
249
|
+
${theme.primary('/recap [on|off]'.padEnd(22))} ${theme.dim('Toggle short summary line after each agent turn')}
|
|
248
250
|
|
|
249
251
|
${chalk.hex('#4169e1').bold(' Visualization & Brain')}
|
|
250
252
|
${theme.primary('/brain'.padEnd(22))} ${theme.dim('Show brain scope + open 3D visualization')}
|
|
@@ -508,6 +510,109 @@ export async function chatCommand(options) {
|
|
|
508
510
|
let roundToolCalls = 0;
|
|
509
511
|
let currentStepLabel = '';
|
|
510
512
|
let currentStepFile = '';
|
|
513
|
+
// Recap tracking — per-round snapshot so we can summarise what just happened.
|
|
514
|
+
let roundStartTokensIn = 0;
|
|
515
|
+
let roundStartTokensOut = 0;
|
|
516
|
+
let roundStartTime = 0;
|
|
517
|
+
const roundToolCounts = new Map();
|
|
518
|
+
const roundFilesTouched = new Set();
|
|
519
|
+
let recapEnabled = true; // Can be toggled via /recap
|
|
520
|
+
function recordRoundTool(toolName, input) {
|
|
521
|
+
roundToolCounts.set(toolName, (roundToolCounts.get(toolName) ?? 0) + 1);
|
|
522
|
+
const fileTools = new Set(['read_file', 'write_file', 'edit_file']);
|
|
523
|
+
if (fileTools.has(toolName)) {
|
|
524
|
+
const p = typeof input?.path === 'string' ? input.path : null;
|
|
525
|
+
if (p)
|
|
526
|
+
roundFilesTouched.add(p);
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
function buildRecapLine() {
|
|
530
|
+
if (!recapEnabled)
|
|
531
|
+
return null;
|
|
532
|
+
const totalTools = [...roundToolCounts.values()].reduce((a, b) => a + b, 0);
|
|
533
|
+
const tokensIn = sessionTokensInput - roundStartTokensIn;
|
|
534
|
+
const tokensOut = sessionTokensOutput - roundStartTokensOut;
|
|
535
|
+
const elapsedMs = Date.now() - roundStartTime;
|
|
536
|
+
if (totalTools === 0 && tokensIn === 0 && tokensOut === 0)
|
|
537
|
+
return null;
|
|
538
|
+
const parts = [];
|
|
539
|
+
// Tool breakdown — compact verbs. Group reads (read_file/list_directory/
|
|
540
|
+
// search_files/find_files), writes (write_file/edit_file), shell, other.
|
|
541
|
+
const reads = (roundToolCounts.get('read_file') ?? 0)
|
|
542
|
+
+ (roundToolCounts.get('list_directory') ?? 0)
|
|
543
|
+
+ (roundToolCounts.get('search_files') ?? 0)
|
|
544
|
+
+ (roundToolCounts.get('find_files') ?? 0);
|
|
545
|
+
const writes = (roundToolCounts.get('write_file') ?? 0)
|
|
546
|
+
+ (roundToolCounts.get('edit_file') ?? 0);
|
|
547
|
+
const runs = roundToolCounts.get('run_command') ?? 0;
|
|
548
|
+
const gitOps = [...roundToolCounts.entries()]
|
|
549
|
+
.filter(([k]) => k.startsWith('git_'))
|
|
550
|
+
.reduce((sum, [, n]) => sum + n, 0);
|
|
551
|
+
const spiralOps = [...roundToolCounts.entries()]
|
|
552
|
+
.filter(([k]) => k.startsWith('spiral_'))
|
|
553
|
+
.reduce((sum, [, n]) => sum + n, 0);
|
|
554
|
+
const browserOps = [...roundToolCounts.entries()]
|
|
555
|
+
.filter(([k]) => k.startsWith('browser_'))
|
|
556
|
+
.reduce((sum, [, n]) => sum + n, 0);
|
|
557
|
+
if (reads > 0)
|
|
558
|
+
parts.push(`${reads} read${reads === 1 ? '' : 's'}`);
|
|
559
|
+
if (writes > 0) {
|
|
560
|
+
const fileNames = [...roundFilesTouched]
|
|
561
|
+
.map(p => p.split(/[\/\\]/).pop() ?? p)
|
|
562
|
+
.slice(0, 2);
|
|
563
|
+
if (writes === 1 && fileNames.length === 1) {
|
|
564
|
+
parts.push(`edited ${fileNames[0]}`);
|
|
565
|
+
}
|
|
566
|
+
else if (fileNames.length > 0) {
|
|
567
|
+
const suffix = writes > fileNames.length ? `+${writes - fileNames.length}` : '';
|
|
568
|
+
parts.push(`edited ${fileNames.join(', ')}${suffix}`);
|
|
569
|
+
}
|
|
570
|
+
else {
|
|
571
|
+
parts.push(`${writes} edit${writes === 1 ? '' : 's'}`);
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
if (runs > 0)
|
|
575
|
+
parts.push(`${runs} shell`);
|
|
576
|
+
if (gitOps > 0)
|
|
577
|
+
parts.push(`${gitOps} git`);
|
|
578
|
+
if (spiralOps > 0)
|
|
579
|
+
parts.push(`${spiralOps} spiral`);
|
|
580
|
+
if (browserOps > 0)
|
|
581
|
+
parts.push(`${browserOps} browser`);
|
|
582
|
+
// Other tools not caught above
|
|
583
|
+
const known = new Set([
|
|
584
|
+
'read_file', 'list_directory', 'search_files', 'find_files',
|
|
585
|
+
'write_file', 'edit_file', 'run_command',
|
|
586
|
+
]);
|
|
587
|
+
const otherTotal = [...roundToolCounts.entries()]
|
|
588
|
+
.filter(([k]) => !known.has(k) && !k.startsWith('git_') && !k.startsWith('spiral_') && !k.startsWith('browser_'))
|
|
589
|
+
.reduce((sum, [, n]) => sum + n, 0);
|
|
590
|
+
if (otherTotal > 0)
|
|
591
|
+
parts.push(`${otherTotal} other`);
|
|
592
|
+
// Tokens
|
|
593
|
+
const totalTokens = tokensIn + tokensOut;
|
|
594
|
+
if (totalTokens >= 1000) {
|
|
595
|
+
parts.push(`${(totalTokens / 1000).toFixed(1)}k tokens`);
|
|
596
|
+
}
|
|
597
|
+
else if (totalTokens > 0) {
|
|
598
|
+
parts.push(`${totalTokens} tokens`);
|
|
599
|
+
}
|
|
600
|
+
// Time
|
|
601
|
+
if (elapsedMs >= 1000) {
|
|
602
|
+
const secs = Math.round(elapsedMs / 1000);
|
|
603
|
+
if (secs >= 60) {
|
|
604
|
+
const m = Math.floor(secs / 60);
|
|
605
|
+
const s = secs % 60;
|
|
606
|
+
parts.push(`${m}m${s > 0 ? ` ${s}s` : ''}`);
|
|
607
|
+
}
|
|
608
|
+
else {
|
|
609
|
+
parts.push(`${secs}s`);
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
if (parts.length === 0)
|
|
613
|
+
return null;
|
|
614
|
+
return chalk.dim(` \u258E Recap: ${parts.join(' \u00B7 ')}`);
|
|
615
|
+
}
|
|
511
616
|
// Timer tracking
|
|
512
617
|
const sessionStartTime = Date.now();
|
|
513
618
|
let currentSection = null;
|
|
@@ -2956,6 +3061,24 @@ export async function chatCommand(options) {
|
|
|
2956
3061
|
}
|
|
2957
3062
|
// Persist to JSONL history (async, non-blocking)
|
|
2958
3063
|
promptHistory.add(input, process.cwd()).catch(() => { });
|
|
3064
|
+
// Handle /recap here (toggles local recapEnabled state in the closure).
|
|
3065
|
+
const trimmedForRecap = input.trim();
|
|
3066
|
+
if (trimmedForRecap === '/recap' || trimmedForRecap.startsWith('/recap ')) {
|
|
3067
|
+
const arg = trimmedForRecap.split(/\s+/)[1]?.toLowerCase();
|
|
3068
|
+
if (arg === 'on') {
|
|
3069
|
+
recapEnabled = true;
|
|
3070
|
+
renderInfo('Recap enabled \u2014 summary line after every agent turn.');
|
|
3071
|
+
}
|
|
3072
|
+
else if (arg === 'off') {
|
|
3073
|
+
recapEnabled = false;
|
|
3074
|
+
renderInfo('Recap disabled.');
|
|
3075
|
+
}
|
|
3076
|
+
else {
|
|
3077
|
+
renderInfo(`Recap is ${recapEnabled ? 'ON' : 'OFF'}. Use /recap on | off to toggle.`);
|
|
3078
|
+
}
|
|
3079
|
+
showPrompt();
|
|
3080
|
+
return;
|
|
3081
|
+
}
|
|
2959
3082
|
// Handle /feed directly here (needs access to inlineProgressActive flag)
|
|
2960
3083
|
if (input.startsWith('/feed')) {
|
|
2961
3084
|
const activeSpiral = spiralEngine ?? await ensureSpiralEngine(brainScope);
|
|
@@ -3547,6 +3670,12 @@ export async function chatCommand(options) {
|
|
|
3547
3670
|
roundToolCalls = 0;
|
|
3548
3671
|
currentStepLabel = '';
|
|
3549
3672
|
currentStepFile = '';
|
|
3673
|
+
// Recap: snapshot round-start state.
|
|
3674
|
+
roundStartTokensIn = sessionTokensInput;
|
|
3675
|
+
roundStartTokensOut = sessionTokensOutput;
|
|
3676
|
+
roundStartTime = Date.now();
|
|
3677
|
+
roundToolCounts.clear();
|
|
3678
|
+
roundFilesTouched.clear();
|
|
3550
3679
|
suggestionPanel.close(); // Close suggestions when agent starts
|
|
3551
3680
|
agentRunning = true;
|
|
3552
3681
|
chrome.promptActive = false; // Re-enable stdout hook redraws for agent output
|
|
@@ -3763,9 +3892,13 @@ export async function chatCommand(options) {
|
|
|
3763
3892
|
await sendAgentMessage(input, agentHistory, provider, project, spiralEngine, config, permissions, undoStack, checkpointStore, agentController, activity, sessionBuffer, (inp, out) => {
|
|
3764
3893
|
sessionTokensInput += inp;
|
|
3765
3894
|
sessionTokensOutput += out;
|
|
3766
|
-
}, () => {
|
|
3895
|
+
}, (toolName) => {
|
|
3767
3896
|
sessionToolCalls++;
|
|
3768
3897
|
roundToolCalls++;
|
|
3898
|
+
// Recap: record tool invocation by name.
|
|
3899
|
+
if (typeof toolName === 'string') {
|
|
3900
|
+
recordRoundTool(toolName, undefined);
|
|
3901
|
+
}
|
|
3769
3902
|
}, () => {
|
|
3770
3903
|
// Activity started — readline stays active for type-ahead buffering.
|
|
3771
3904
|
// Muting is handled by activity.setMuteCallbacks (mute during LLM stream,
|
|
@@ -3774,11 +3907,26 @@ export async function chatCommand(options) {
|
|
|
3774
3907
|
}, effectiveValidation, bugJournal, browserController, visionProcessor, pushScreenshotToBrainFn, getJarvisContextForPrompt(), (label, tool) => {
|
|
3775
3908
|
currentStepLabel = label;
|
|
3776
3909
|
const fileTools = new Set(['read_file', 'write_file', 'edit_file']);
|
|
3777
|
-
|
|
3910
|
+
if (fileTools.has(tool)) {
|
|
3911
|
+
const file = label.replace(/^(reading|writing|editing)\s+/, '');
|
|
3912
|
+
currentStepFile = file;
|
|
3913
|
+
// Recap: track files touched so the summary can name them.
|
|
3914
|
+
if (file && (tool === 'write_file' || tool === 'edit_file')) {
|
|
3915
|
+
roundFilesTouched.add(file);
|
|
3916
|
+
}
|
|
3917
|
+
}
|
|
3918
|
+
else {
|
|
3919
|
+
currentStepFile = '';
|
|
3920
|
+
}
|
|
3778
3921
|
}, jarvisLearning);
|
|
3779
3922
|
}
|
|
3780
3923
|
}
|
|
3781
3924
|
agentRunning = false;
|
|
3925
|
+
// Recap: emit a short summary of what just happened.
|
|
3926
|
+
const recapLine = buildRecapLine();
|
|
3927
|
+
if (recapLine) {
|
|
3928
|
+
process.stdout.write(recapLine + '\n');
|
|
3929
|
+
}
|
|
3782
3930
|
// Keep simple message history for state persistence.
|
|
3783
3931
|
// FIX: CHATFLOW-001 — also persist the assistant's reply, otherwise
|
|
3784
3932
|
// saveState() writes a user-only transcript and checkpoint browser shows
|