vigthoria-cli 1.11.10 → 1.11.11
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/commands/chat.d.ts
CHANGED
|
@@ -48,6 +48,7 @@ export declare class ChatCommand {
|
|
|
48
48
|
private retryPromptStreak;
|
|
49
49
|
private v3SuppressThinkingStream;
|
|
50
50
|
private v3StreamedAnswerBuffer;
|
|
51
|
+
private v3StreamedAnswerDisplayed;
|
|
51
52
|
private v3SeenToolCalls;
|
|
52
53
|
private v3SeenToolResults;
|
|
53
54
|
private lastAgentRunOutcome;
|
|
@@ -123,6 +124,9 @@ export declare class ChatCommand {
|
|
|
123
124
|
private isRawV3StreamPayload;
|
|
124
125
|
private consumeV3StreamPayload;
|
|
125
126
|
private writeV3StreamText;
|
|
127
|
+
private displayV3StreamedAnswer;
|
|
128
|
+
private renderAgentAnswerForTerminal;
|
|
129
|
+
private getTerminalContentWidth;
|
|
126
130
|
private sanitizeV3VisibleStreamText;
|
|
127
131
|
private writeAgentActivityLine;
|
|
128
132
|
private updateV3AgentSpinner;
|
package/dist/commands/chat.js
CHANGED
|
@@ -14,6 +14,7 @@ import { ProjectMemoryService } from '../utils/project-memory.js';
|
|
|
14
14
|
import { buildPersonaOverlay, normalizePersonaMode } from '../utils/persona.js';
|
|
15
15
|
import { runAgentSessionMenu, shouldShowAgentSessionMenu } from './agent-session-menu.js';
|
|
16
16
|
import { createLiveOutcome, evaluateExecutorSuccess, handleTaskEvent, isSubstantiveAgentAnswer, isToolEvidenceStubAnswer, normalizeAgentAnswerContent, noteAnalysisToolUse, } from '../utils/agentRunOutcome.js';
|
|
17
|
+
import { looksLikeMarkdownReport, renderMarkdownToTerminal, summarizeMarkdownReport, } from '../utils/terminalMarkdown.js';
|
|
17
18
|
const DEFAULT_V3_AGENT_TIMEOUT_MS = (() => {
|
|
18
19
|
const rawValue = process.env.VIGTHORIA_AGENT_TIMEOUT_MS || process.env.V3_AGENT_TIMEOUT_MS;
|
|
19
20
|
if (!rawValue) {
|
|
@@ -67,6 +68,7 @@ export class ChatCommand {
|
|
|
67
68
|
retryPromptStreak = 0;
|
|
68
69
|
v3SuppressThinkingStream = false;
|
|
69
70
|
v3StreamedAnswerBuffer = '';
|
|
71
|
+
v3StreamedAnswerDisplayed = false;
|
|
70
72
|
v3SeenToolCalls = new Set();
|
|
71
73
|
v3SeenToolResults = new Set();
|
|
72
74
|
// Last completed Agent run — used by /retry, /continue, and the final summary block.
|
|
@@ -788,8 +790,32 @@ export class ChatCommand {
|
|
|
788
790
|
else {
|
|
789
791
|
spinner.stop();
|
|
790
792
|
}
|
|
791
|
-
process.stdout.write(safeText);
|
|
792
793
|
this.v3StreamedAnswerBuffer += safeText;
|
|
794
|
+
spinner.text = looksLikeMarkdownReport(this.v3StreamedAnswerBuffer)
|
|
795
|
+
? 'Writing analysis report...'
|
|
796
|
+
: 'Writing response...';
|
|
797
|
+
}
|
|
798
|
+
displayV3StreamedAnswer() {
|
|
799
|
+
if (this.jsonOutput || this.v3StreamedAnswerDisplayed) {
|
|
800
|
+
return;
|
|
801
|
+
}
|
|
802
|
+
const content = this.v3StreamedAnswerBuffer.trim();
|
|
803
|
+
if (!isSubstantiveAgentAnswer(content)) {
|
|
804
|
+
return;
|
|
805
|
+
}
|
|
806
|
+
console.log('');
|
|
807
|
+
console.log(renderMarkdownToTerminal(content, this.getTerminalContentWidth()));
|
|
808
|
+
this.v3StreamedAnswerDisplayed = true;
|
|
809
|
+
}
|
|
810
|
+
renderAgentAnswerForTerminal(content) {
|
|
811
|
+
const normalized = String(content || '').trim();
|
|
812
|
+
if (!normalized)
|
|
813
|
+
return '';
|
|
814
|
+
return renderMarkdownToTerminal(normalized, this.getTerminalContentWidth());
|
|
815
|
+
}
|
|
816
|
+
getTerminalContentWidth() {
|
|
817
|
+
const cols = process.stdout.columns || 80;
|
|
818
|
+
return Math.max(60, Math.min(cols - 2, 100));
|
|
793
819
|
}
|
|
794
820
|
sanitizeV3VisibleStreamText(text) {
|
|
795
821
|
let output = String(text || '');
|
|
@@ -923,12 +949,15 @@ export class ChatCommand {
|
|
|
923
949
|
if (event.type === 'thinking') {
|
|
924
950
|
this.v3IterationCount += 1;
|
|
925
951
|
const iterText = this.sanitizeServerPath(event.content || '');
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
952
|
+
const isGenericStep = !iterText
|
|
953
|
+
|| /read-only analysis turn|run at least one discovery tool/i.test(iterText)
|
|
954
|
+
|| /^Step \d+:/i.test(iterText)
|
|
955
|
+
|| /reviewing attached files|inspecting workspace/i.test(iterText);
|
|
956
|
+
if (!isGenericStep) {
|
|
957
|
+
if (spinner.isSpinning)
|
|
958
|
+
spinner.stop();
|
|
959
|
+
this.writeAgentActivityLine(chalk.cyan(`\n── ${this.fitTerminalText(iterText, 6)} ──\n`));
|
|
960
|
+
}
|
|
932
961
|
spinner.text = 'Analyzing...';
|
|
933
962
|
return;
|
|
934
963
|
}
|
|
@@ -951,6 +980,7 @@ export class ChatCommand {
|
|
|
951
980
|
const tools = event.tool_calls || this.v3ToolCallCount;
|
|
952
981
|
if (spinner.isSpinning)
|
|
953
982
|
spinner.stop();
|
|
983
|
+
this.displayV3StreamedAnswer();
|
|
954
984
|
let statLine = `${iters} iterations, ${tools} tool calls`;
|
|
955
985
|
if (elapsed)
|
|
956
986
|
statLine += `, ${elapsed}`;
|
|
@@ -2545,6 +2575,7 @@ export class ChatCommand {
|
|
|
2545
2575
|
this.v3LastActivity = Date.now();
|
|
2546
2576
|
this.v3StreamingStarted = false;
|
|
2547
2577
|
this.v3StreamedAnswerBuffer = '';
|
|
2578
|
+
this.v3StreamedAnswerDisplayed = false;
|
|
2548
2579
|
this.v3SeenToolCalls.clear();
|
|
2549
2580
|
this.v3SeenToolResults.clear();
|
|
2550
2581
|
const taskDisplay = new TaskDisplay(['Analyse workspace', 'Execute tasks', 'Validate output', 'Self-heal'], false);
|
|
@@ -2731,9 +2762,8 @@ export class ChatCommand {
|
|
|
2731
2762
|
if (spinner) {
|
|
2732
2763
|
spinner.stop();
|
|
2733
2764
|
}
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
process.stdout.write('\n');
|
|
2765
|
+
if (this.v3StreamingStarted && !this.v3StreamedAnswerDisplayed) {
|
|
2766
|
+
this.displayV3StreamedAnswer();
|
|
2737
2767
|
}
|
|
2738
2768
|
const previewGate = (response.metadata?.previewGate || null);
|
|
2739
2769
|
const workspaceHasOutput = this.api.hasAgentWorkspaceOutput(workspaceContext);
|
|
@@ -2828,15 +2858,13 @@ export class ChatCommand {
|
|
|
2828
2858
|
executorSucceeded = false;
|
|
2829
2859
|
}
|
|
2830
2860
|
if (!this.jsonOutput && !this.directPromptMode) {
|
|
2831
|
-
if (this.
|
|
2832
|
-
|
|
2833
|
-
console.log(chalk.bold('Answer:'));
|
|
2834
|
-
console.log(this.v3StreamedAnswerBuffer.trim());
|
|
2861
|
+
if (this.v3StreamedAnswerDisplayed) {
|
|
2862
|
+
// Highlighted report already printed once above.
|
|
2835
2863
|
}
|
|
2836
2864
|
else if (isSubstantiveAgentAnswer(finalAnswer)) {
|
|
2837
2865
|
console.log('');
|
|
2838
2866
|
console.log(chalk.bold('Answer:'));
|
|
2839
|
-
console.log(finalAnswer);
|
|
2867
|
+
console.log(this.renderAgentAnswerForTerminal(finalAnswer));
|
|
2840
2868
|
}
|
|
2841
2869
|
else if (!requiresWorkspaceChanges) {
|
|
2842
2870
|
console.log('');
|
|
@@ -2845,7 +2873,7 @@ export class ChatCommand {
|
|
|
2845
2873
|
}
|
|
2846
2874
|
else if (finalAnswer) {
|
|
2847
2875
|
console.log('');
|
|
2848
|
-
console.log(finalAnswer);
|
|
2876
|
+
console.log(this.renderAgentAnswerForTerminal(finalAnswer));
|
|
2849
2877
|
}
|
|
2850
2878
|
}
|
|
2851
2879
|
if (!executorSucceeded && requiresWorkspaceChanges && changedFileCount === 0 && !liveOutcome.executorError) {
|
|
@@ -3456,10 +3484,20 @@ export class ChatCommand {
|
|
|
3456
3484
|
console.log(' ' + chalk.white(taskLine + '.'));
|
|
3457
3485
|
}
|
|
3458
3486
|
else if (outcome.answerContent && isSubstantiveAgentAnswer(outcome.answerContent)) {
|
|
3459
|
-
const
|
|
3460
|
-
|
|
3461
|
-
|
|
3462
|
-
|
|
3487
|
+
const reportSummary = summarizeMarkdownReport(outcome.answerContent);
|
|
3488
|
+
if (reportSummary) {
|
|
3489
|
+
const sectionPreview = reportSummary.sections.length > 0
|
|
3490
|
+
? reportSummary.sections.slice(0, 4).join(', ')
|
|
3491
|
+
: `${Math.round(reportSummary.charCount / 1000)}k chars`;
|
|
3492
|
+
console.log(' ' + chalk.white(reportSummary.title));
|
|
3493
|
+
console.log(' ' + chalk.gray(`Sections: ${sectionPreview}`));
|
|
3494
|
+
}
|
|
3495
|
+
else {
|
|
3496
|
+
const preview = outcome.answerContent.length > 160
|
|
3497
|
+
? `${outcome.answerContent.slice(0, 160)}…`
|
|
3498
|
+
: outcome.answerContent;
|
|
3499
|
+
console.log(' ' + chalk.white(preview));
|
|
3500
|
+
}
|
|
3463
3501
|
}
|
|
3464
3502
|
else if (changedFileCount > 0) {
|
|
3465
3503
|
console.log(' ' + chalk.white('Workspace changes were produced and are ready for review.'));
|
package/dist/utils/api.js
CHANGED
|
@@ -1524,7 +1524,7 @@ export class APIClient {
|
|
|
1524
1524
|
if (json.length <= LIMIT)
|
|
1525
1525
|
return json;
|
|
1526
1526
|
if (process.env.DEBUG || process.env.VIGTHORIA_DEBUG) {
|
|
1527
|
-
|
|
1527
|
+
process.stderr.write(`[context] Payload ${json.length} chars exceeds ${LIMIT} limit, compacting...\n`);
|
|
1528
1528
|
}
|
|
1529
1529
|
// Phase 1 — shrink workspaceFiles to fit
|
|
1530
1530
|
const summary = payload.localWorkspaceSummary;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared terminal markdown rendering for CLI commands.
|
|
3
|
+
*/
|
|
4
|
+
export interface MarkdownReportSummary {
|
|
5
|
+
title: string;
|
|
6
|
+
sections: string[];
|
|
7
|
+
charCount: number;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Clean marked-terminal output for release-grade CLI presentation.
|
|
11
|
+
*/
|
|
12
|
+
export declare function cleanTerminalMarkdownOutput(raw: string): string;
|
|
13
|
+
export declare function looksLikeMarkdownReport(text: string): boolean;
|
|
14
|
+
export declare function renderMarkdownToTerminal(markdown: string, width?: number): string;
|
|
15
|
+
export declare function summarizeMarkdownReport(markdown: string): MarkdownReportSummary | null;
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared terminal markdown rendering for CLI commands.
|
|
3
|
+
*/
|
|
4
|
+
import { Marked } from 'marked';
|
|
5
|
+
import { markedTerminal } from 'marked-terminal';
|
|
6
|
+
let cachedRenderer = null;
|
|
7
|
+
function getTerminalWidth() {
|
|
8
|
+
const cols = process.stdout.columns || 80;
|
|
9
|
+
return Math.max(60, Math.min(cols - 2, 100));
|
|
10
|
+
}
|
|
11
|
+
function getRenderer(width) {
|
|
12
|
+
const resolvedWidth = width ?? getTerminalWidth();
|
|
13
|
+
if (cachedRenderer && cachedRenderer.width === resolvedWidth) {
|
|
14
|
+
return cachedRenderer.marked;
|
|
15
|
+
}
|
|
16
|
+
const marked = new Marked();
|
|
17
|
+
marked.use(markedTerminal({
|
|
18
|
+
showSectionPrefix: false,
|
|
19
|
+
tab: 2,
|
|
20
|
+
width: resolvedWidth,
|
|
21
|
+
reflowText: true,
|
|
22
|
+
}));
|
|
23
|
+
cachedRenderer = { width: resolvedWidth, marked };
|
|
24
|
+
return marked;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Clean marked-terminal output for release-grade CLI presentation.
|
|
28
|
+
*/
|
|
29
|
+
export function cleanTerminalMarkdownOutput(raw) {
|
|
30
|
+
let out = raw;
|
|
31
|
+
out = out.replace(/^ \* /gm, '- ');
|
|
32
|
+
out = out.replace(/^ \* /gm, ' - ');
|
|
33
|
+
const stripAnsi = (s) => s.replace(/\x1b\[[0-9;]*m/g, '');
|
|
34
|
+
out = out.split('\n').filter((line) => {
|
|
35
|
+
if (line === '')
|
|
36
|
+
return true;
|
|
37
|
+
return stripAnsi(line).trim().length > 0;
|
|
38
|
+
}).join('\n');
|
|
39
|
+
out = out.replace(/\n{3,}/g, '\n\n');
|
|
40
|
+
return out;
|
|
41
|
+
}
|
|
42
|
+
export function looksLikeMarkdownReport(text) {
|
|
43
|
+
const trimmed = String(text || '').trim();
|
|
44
|
+
if (!trimmed)
|
|
45
|
+
return false;
|
|
46
|
+
return /^#{1,3}\s+\S/m.test(trimmed)
|
|
47
|
+
|| /^\|.+\|/m.test(trimmed)
|
|
48
|
+
|| /^[-*]\s+\*\*/m.test(trimmed);
|
|
49
|
+
}
|
|
50
|
+
export function renderMarkdownToTerminal(markdown, width) {
|
|
51
|
+
const input = String(markdown || '').trim();
|
|
52
|
+
if (!input)
|
|
53
|
+
return '';
|
|
54
|
+
if (!looksLikeMarkdownReport(input)) {
|
|
55
|
+
return input;
|
|
56
|
+
}
|
|
57
|
+
const rendered = getRenderer(width).parse(input);
|
|
58
|
+
return cleanTerminalMarkdownOutput(rendered);
|
|
59
|
+
}
|
|
60
|
+
export function summarizeMarkdownReport(markdown) {
|
|
61
|
+
const text = String(markdown || '').trim();
|
|
62
|
+
if (!text || !looksLikeMarkdownReport(text)) {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
const lines = text.split('\n');
|
|
66
|
+
let title = '';
|
|
67
|
+
const sections = [];
|
|
68
|
+
for (const line of lines) {
|
|
69
|
+
const h1 = line.match(/^#\s+(.+)$/);
|
|
70
|
+
if (h1 && !title) {
|
|
71
|
+
title = h1[1].replace(/[*_`]/g, '').trim();
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
const h2 = line.match(/^##\s+(.+)$/);
|
|
75
|
+
if (h2) {
|
|
76
|
+
const section = h2[1].replace(/[*_`]/g, '').trim();
|
|
77
|
+
if (section && sections.length < 8) {
|
|
78
|
+
sections.push(section);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
if (!title) {
|
|
83
|
+
const firstLine = lines.find((line) => line.trim().length > 0)?.trim() || 'Analysis report';
|
|
84
|
+
title = firstLine.replace(/^#+\s*/, '').replace(/[*_`]/g, '').slice(0, 120);
|
|
85
|
+
}
|
|
86
|
+
return {
|
|
87
|
+
title,
|
|
88
|
+
sections,
|
|
89
|
+
charCount: text.length,
|
|
90
|
+
};
|
|
91
|
+
}
|