vigthoria-cli 1.11.8 → 1.11.10
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/agent-session-menu.js +18 -9
- package/dist/commands/chat.d.ts +6 -0
- package/dist/commands/chat.js +73 -33
- package/dist/index.js +23 -11
- package/dist/utils/agentRunOutcome.js +24 -0
- package/dist/utils/api.js +1 -2
- package/dist/utils/logger.js +6 -1
- package/package.json +1 -1
|
@@ -6,6 +6,15 @@ import inquirer from 'inquirer';
|
|
|
6
6
|
import * as fs from 'fs';
|
|
7
7
|
import * as os from 'os';
|
|
8
8
|
import * as path from 'path';
|
|
9
|
+
function terminalColumns() {
|
|
10
|
+
const raw = Number(process.stdout.columns || 80);
|
|
11
|
+
return Number.isFinite(raw) && raw > 0 ? raw : 80;
|
|
12
|
+
}
|
|
13
|
+
function fitLine(text, reserve = 0) {
|
|
14
|
+
const width = Math.max(24, terminalColumns() - reserve);
|
|
15
|
+
const clean = String(text || '').replace(/\s+/g, ' ').trim();
|
|
16
|
+
return clean.length > width ? `${clean.slice(0, Math.max(1, width - 1))}…` : clean;
|
|
17
|
+
}
|
|
9
18
|
function validateExistingDirectory(input) {
|
|
10
19
|
const trimmed = String(input || '').trim().replace(/^['"]|['"]$/g, '');
|
|
11
20
|
if (!trimmed) {
|
|
@@ -84,19 +93,19 @@ export async function runAgentSessionMenu(defaults = {}) {
|
|
|
84
93
|
};
|
|
85
94
|
console.log();
|
|
86
95
|
console.log(chalk.cyan('═══ Agent Session Setup ═══'));
|
|
87
|
-
console.log(chalk.gray(`Workspace: ${session.workspacePath}`));
|
|
88
|
-
console.log(chalk.gray(`Debug: ${session.debugMode ? 'on' : 'off'} | Auto-approve: ${session.autoApprove ? 'on' : 'off'} | Auto-save: ${session.autoSave ? 'on' : 'off'}`));
|
|
96
|
+
console.log(chalk.gray(fitLine(`Workspace: ${session.workspacePath}`)));
|
|
97
|
+
console.log(chalk.gray(fitLine(`Debug: ${session.debugMode ? 'on' : 'off'} | Auto-approve: ${session.autoApprove ? 'on' : 'off'} | Auto-save: ${session.autoSave ? 'on' : 'off'}`)));
|
|
89
98
|
console.log();
|
|
90
99
|
const { action } = await inquirer.prompt([
|
|
91
100
|
{
|
|
92
101
|
type: 'list',
|
|
93
102
|
name: 'action',
|
|
94
|
-
message: '
|
|
103
|
+
message: 'Session',
|
|
95
104
|
choices: [
|
|
96
|
-
{ name: 'Start
|
|
97
|
-
{ name: 'Set workspace
|
|
98
|
-
{ name: 'Create
|
|
99
|
-
{ name: '
|
|
105
|
+
{ name: 'Start now', value: 'start' },
|
|
106
|
+
{ name: 'Set workspace', value: 'set-workspace' },
|
|
107
|
+
{ name: 'Create workspace', value: 'create-workspace' },
|
|
108
|
+
{ name: 'Settings', value: 'settings' },
|
|
100
109
|
],
|
|
101
110
|
},
|
|
102
111
|
]);
|
|
@@ -153,8 +162,8 @@ export async function runAgentSessionMenu(defaults = {}) {
|
|
|
153
162
|
}
|
|
154
163
|
console.log();
|
|
155
164
|
console.log(chalk.cyan('── Session ready ──'));
|
|
156
|
-
console.log(chalk.gray(`Workspace: ${session.workspacePath}`));
|
|
157
|
-
console.log(chalk.gray(`Debug: ${session.debugMode ? 'on' : 'off'} | Auto-approve: ${session.autoApprove ? 'on' : 'off'} | Auto-save: ${session.autoSave ? 'on' : 'off'}`));
|
|
165
|
+
console.log(chalk.gray(fitLine(`Workspace: ${session.workspacePath}`)));
|
|
166
|
+
console.log(chalk.gray(fitLine(`Debug: ${session.debugMode ? 'on' : 'off'} | Auto-approve: ${session.autoApprove ? 'on' : 'off'} | Auto-save: ${session.autoSave ? 'on' : 'off'}`)));
|
|
158
167
|
console.log();
|
|
159
168
|
return session;
|
|
160
169
|
}
|
package/dist/commands/chat.d.ts
CHANGED
|
@@ -48,6 +48,8 @@ export declare class ChatCommand {
|
|
|
48
48
|
private retryPromptStreak;
|
|
49
49
|
private v3SuppressThinkingStream;
|
|
50
50
|
private v3StreamedAnswerBuffer;
|
|
51
|
+
private v3SeenToolCalls;
|
|
52
|
+
private v3SeenToolResults;
|
|
51
53
|
private lastAgentRunOutcome;
|
|
52
54
|
private isJwtExpirationError;
|
|
53
55
|
private isNetworkError;
|
|
@@ -114,6 +116,10 @@ export declare class ChatCommand {
|
|
|
114
116
|
private sanitizeServerPath;
|
|
115
117
|
private stripHiddenThoughtBlocks;
|
|
116
118
|
private describeV3AgentTool;
|
|
119
|
+
private terminalColumns;
|
|
120
|
+
private fitTerminalText;
|
|
121
|
+
private normalizeToolOutputForDisplay;
|
|
122
|
+
private toolEventKey;
|
|
117
123
|
private isRawV3StreamPayload;
|
|
118
124
|
private consumeV3StreamPayload;
|
|
119
125
|
private writeV3StreamText;
|
package/dist/commands/chat.js
CHANGED
|
@@ -67,6 +67,8 @@ export class ChatCommand {
|
|
|
67
67
|
retryPromptStreak = 0;
|
|
68
68
|
v3SuppressThinkingStream = false;
|
|
69
69
|
v3StreamedAnswerBuffer = '';
|
|
70
|
+
v3SeenToolCalls = new Set();
|
|
71
|
+
v3SeenToolResults = new Set();
|
|
70
72
|
// Last completed Agent run — used by /retry, /continue, and the final summary block.
|
|
71
73
|
lastAgentRunOutcome = null;
|
|
72
74
|
isJwtExpirationError(error) {
|
|
@@ -706,6 +708,33 @@ export class ChatCommand {
|
|
|
706
708
|
}
|
|
707
709
|
return 'Working';
|
|
708
710
|
}
|
|
711
|
+
terminalColumns() {
|
|
712
|
+
const raw = Number(process.stdout.columns || process.stderr.columns || 80);
|
|
713
|
+
return Number.isFinite(raw) && raw > 0 ? raw : 80;
|
|
714
|
+
}
|
|
715
|
+
fitTerminalText(text, reserve = 0) {
|
|
716
|
+
const width = Math.max(24, this.terminalColumns() - reserve);
|
|
717
|
+
const clean = String(text || '').replace(/\s+/g, ' ').trim();
|
|
718
|
+
const visible = clean.replace(/\x1B\[[0-9;]*[a-zA-Z]/g, '');
|
|
719
|
+
if (visible.length <= width)
|
|
720
|
+
return clean;
|
|
721
|
+
return `${visible.slice(0, Math.max(1, width - 1))}…`;
|
|
722
|
+
}
|
|
723
|
+
normalizeToolOutputForDisplay(output) {
|
|
724
|
+
return String(output || '')
|
|
725
|
+
.replace(/\/r\/n|\/n|\\n/g, '\n')
|
|
726
|
+
.replace(/\/r|\\r/g, '')
|
|
727
|
+
.replace(/\t/g, ' ');
|
|
728
|
+
}
|
|
729
|
+
toolEventKey(event) {
|
|
730
|
+
const name = String(event?.name || event?.tool || event?.tool_name || '').trim();
|
|
731
|
+
const args = event?.arguments && typeof event.arguments === 'object' ? event.arguments : {};
|
|
732
|
+
const target = String(args.path || args.file_path || args.pattern || args.command || event?.target || '').trim();
|
|
733
|
+
if (target)
|
|
734
|
+
return `${name}:${target}`;
|
|
735
|
+
const output = typeof event?.output === 'string' ? event.output.replace(/\s+/g, ' ').slice(0, 160) : '';
|
|
736
|
+
return `${name}:${output}`;
|
|
737
|
+
}
|
|
709
738
|
isRawV3StreamPayload(event) {
|
|
710
739
|
if (!event) {
|
|
711
740
|
return false;
|
|
@@ -814,15 +843,20 @@ export class ChatCommand {
|
|
|
814
843
|
}
|
|
815
844
|
this.v3LastActivity = Date.now();
|
|
816
845
|
if (event.type === 'tool_call') {
|
|
846
|
+
const eventKey = this.toolEventKey(event);
|
|
847
|
+
if (this.v3SeenToolCalls.has(eventKey)) {
|
|
848
|
+
return;
|
|
849
|
+
}
|
|
850
|
+
this.v3SeenToolCalls.add(eventKey);
|
|
817
851
|
this.v3ToolCallCount += 1;
|
|
818
852
|
const toolDesc = this.describeV3AgentTool(event.tool || event.name || event.tool_name);
|
|
819
853
|
const toolTarget = event.arguments?.path || event.arguments?.file_path || event.arguments?.pattern || '';
|
|
820
854
|
const sanitizedTarget = this.sanitizeServerPath(String(toolTarget));
|
|
821
|
-
const shortTarget = sanitizedTarget ? `
|
|
855
|
+
const shortTarget = sanitizedTarget ? ` -> ${sanitizedTarget.replace(/\\/g, '/').split('/').slice(-2).join('/')}` : '';
|
|
822
856
|
const stepLabel = chalk.cyan(` [${this.v3ToolCallCount}]`) + ` ${toolDesc}${shortTarget}`;
|
|
823
857
|
if (spinner.isSpinning)
|
|
824
858
|
spinner.stop();
|
|
825
|
-
this.writeAgentActivityLine(stepLabel + '\n');
|
|
859
|
+
this.writeAgentActivityLine(this.fitTerminalText(stepLabel) + '\n');
|
|
826
860
|
// Show extra detail for key tools
|
|
827
861
|
const args = event.arguments || {};
|
|
828
862
|
const toolName = event.name || event.tool || '';
|
|
@@ -832,16 +866,21 @@ export class ChatCommand {
|
|
|
832
866
|
}
|
|
833
867
|
else if (toolName === 'bash' && typeof args.command === 'string') {
|
|
834
868
|
const command = this.sanitizeServerPath(args.command);
|
|
835
|
-
this.writeAgentActivityLine(chalk.gray(` $
|
|
869
|
+
this.writeAgentActivityLine(chalk.gray(` ${this.fitTerminalText(`$ ${command}`, 6)}\n`));
|
|
836
870
|
}
|
|
837
871
|
else if (toolName === 'read_file') {
|
|
838
|
-
this.writeAgentActivityLine(chalk.gray(` reading ${sanitizedTarget || 'file'}\n`));
|
|
872
|
+
this.writeAgentActivityLine(chalk.gray(` ${this.fitTerminalText(`reading ${sanitizedTarget || 'file'}`, 6)}\n`));
|
|
839
873
|
}
|
|
840
|
-
spinner.start();
|
|
841
874
|
spinner.text = `Running ${toolDesc}...`;
|
|
842
875
|
return;
|
|
843
876
|
}
|
|
844
877
|
if (event.type === 'tool_result') {
|
|
878
|
+
const eventKey = this.toolEventKey(event);
|
|
879
|
+
if (eventKey && this.v3SeenToolResults.has(eventKey)) {
|
|
880
|
+
return;
|
|
881
|
+
}
|
|
882
|
+
if (eventKey)
|
|
883
|
+
this.v3SeenToolResults.add(eventKey);
|
|
845
884
|
const success = event.success !== false;
|
|
846
885
|
const toolName = event.name || event.tool || '';
|
|
847
886
|
const indicator = success ? chalk.green(' ✓') : chalk.red(' ✗');
|
|
@@ -850,27 +889,30 @@ export class ChatCommand {
|
|
|
850
889
|
this.writeAgentActivityLine(`${indicator} ${toolName}\n`);
|
|
851
890
|
// Show output for failures, or brief summary for successes — sanitize server paths
|
|
852
891
|
const rawOutput = typeof event.output === 'string' ? event.output.trim() : '';
|
|
853
|
-
const output = this.sanitizeServerPath(rawOutput);
|
|
892
|
+
const output = this.normalizeToolOutputForDisplay(this.sanitizeServerPath(rawOutput));
|
|
854
893
|
if (!success && output) {
|
|
855
894
|
const sanitizedError = this.sanitizeServerPath(typeof event.error === 'string' ? event.error : output);
|
|
856
895
|
const lines = sanitizedError.split('\n').slice(0, 4);
|
|
857
|
-
this.writeAgentActivityLine(chalk.red(` ${
|
|
896
|
+
this.writeAgentActivityLine(chalk.red(`${lines.map((line) => ` ${this.fitTerminalText(line, 6)}`).join('\n')}\n`));
|
|
858
897
|
}
|
|
859
898
|
else if (success && output && output.length > 0) {
|
|
860
899
|
if (toolName === 'read_file' || toolName === 'grep' || toolName === 'search_files' || toolName === 'list_directory') {
|
|
861
900
|
const lineCount = output.split('\n').length;
|
|
862
|
-
const preview = output.split('\n')
|
|
901
|
+
const preview = output.split('\n')
|
|
902
|
+
.map((line) => line.trim())
|
|
903
|
+
.filter((line) => line && !line.startsWith('.vigthoria/memory/brain.json:'))
|
|
904
|
+
.slice(0, 3)
|
|
905
|
+
.join('\n');
|
|
863
906
|
this.writeAgentActivityLine(chalk.gray(` ${lineCount} line${lineCount === 1 ? '' : 's'} returned\n`));
|
|
864
907
|
if (preview && preview.length > 20 && !/^\(no matches\)$/i.test(preview.trim())) {
|
|
865
|
-
this.writeAgentActivityLine(chalk.gray(`${preview.split('\n').map((
|
|
908
|
+
this.writeAgentActivityLine(chalk.gray(`${preview.split('\n').map((line) => ` ${this.fitTerminalText(line, 6)}`).join('\n')}\n`));
|
|
866
909
|
}
|
|
867
910
|
}
|
|
868
911
|
else {
|
|
869
|
-
const brief = output.split('\n')[0]
|
|
870
|
-
this.writeAgentActivityLine(chalk.gray(` ${brief
|
|
912
|
+
const brief = output.split('\n')[0];
|
|
913
|
+
this.writeAgentActivityLine(chalk.gray(` ${this.fitTerminalText(brief, 6)}\n`));
|
|
871
914
|
}
|
|
872
915
|
}
|
|
873
|
-
spinner.start();
|
|
874
916
|
spinner.text = 'Next step...';
|
|
875
917
|
return;
|
|
876
918
|
}
|
|
@@ -886,8 +928,7 @@ export class ChatCommand {
|
|
|
886
928
|
const display = iterText && !/read-only analysis turn|run at least one discovery tool/i.test(iterText)
|
|
887
929
|
? iterText
|
|
888
930
|
: `Step ${this.v3IterationCount}: inspecting workspace…`;
|
|
889
|
-
this.writeAgentActivityLine(chalk.cyan(`\n── ${display} ──\n`));
|
|
890
|
-
spinner.start();
|
|
931
|
+
this.writeAgentActivityLine(chalk.cyan(`\n── ${this.fitTerminalText(display, 6)} ──\n`));
|
|
891
932
|
spinner.text = 'Analyzing...';
|
|
892
933
|
return;
|
|
893
934
|
}
|
|
@@ -920,13 +961,13 @@ export class ChatCommand {
|
|
|
920
961
|
if (fail > 0)
|
|
921
962
|
statLine += chalk.yellow(`, ${fail} failed`);
|
|
922
963
|
}
|
|
923
|
-
process.
|
|
964
|
+
process.stdout.write(chalk.green(`\n✓ Complete`) + ` - ${this.fitTerminalText(statLine, 14)}\n`);
|
|
924
965
|
// Show seal quality score if available
|
|
925
966
|
if (event.seal_score && typeof event.seal_score.overall === 'number') {
|
|
926
967
|
const score = event.seal_score.overall;
|
|
927
968
|
const tier = event.seal_score.tier || '';
|
|
928
969
|
const scoreColor = score >= 7 ? chalk.green : score >= 5 ? chalk.yellow : chalk.red;
|
|
929
|
-
process.
|
|
970
|
+
process.stdout.write(chalk.cyan(' [Quality] ') + scoreColor(`${score}/10`) + (tier ? chalk.gray(` (${tier})`) : '') + '\n');
|
|
930
971
|
}
|
|
931
972
|
return;
|
|
932
973
|
}
|
|
@@ -943,35 +984,31 @@ export class ChatCommand {
|
|
|
943
984
|
}
|
|
944
985
|
if (spinner.isSpinning)
|
|
945
986
|
spinner.stop();
|
|
946
|
-
process.
|
|
947
|
-
if (quality)
|
|
948
|
-
process.stderr.write(chalk.gray(` (${quality})`));
|
|
949
|
-
process.stderr.write('\n');
|
|
987
|
+
process.stdout.write(chalk.cyan(` [Plan] `) + this.fitTerminalText(`Task: ${planKind || 'analyzing'}${quality ? ` (${quality})` : ''}`, 9) + '\n');
|
|
950
988
|
if (summary) {
|
|
951
|
-
process.
|
|
989
|
+
process.stdout.write(chalk.gray(` ${this.fitTerminalText(summary, 6)}\n`));
|
|
952
990
|
}
|
|
953
991
|
if (status === 'planning' && Number.isFinite(Number(plan.elapsed_seconds))) {
|
|
954
|
-
process.
|
|
992
|
+
process.stdout.write(chalk.gray(` elapsed: ${plan.elapsed_seconds}s\n`));
|
|
955
993
|
}
|
|
956
994
|
if (Array.isArray(plan.tasks) && plan.tasks.length > 0) {
|
|
957
|
-
process.
|
|
995
|
+
process.stdout.write(chalk.gray(` ${plan.total_tasks || plan.tasks.length} tasks:\n`));
|
|
958
996
|
for (const t of plan.tasks.slice(0, 10)) {
|
|
959
997
|
const targets = Array.isArray(t.targets) && t.targets.length ? ` → ${t.targets.map((target) => this.sanitizeServerPath(String(target))).join(', ')}` : '';
|
|
960
|
-
process.
|
|
998
|
+
process.stdout.write(chalk.gray(` - ${this.fitTerminalText(`${this.sanitizeServerPath(String(t.title || t.id))}${targets}`, 10)}\n`));
|
|
961
999
|
}
|
|
962
1000
|
if (plan.tasks.length > 10) {
|
|
963
|
-
process.
|
|
1001
|
+
process.stdout.write(chalk.gray(` ... and ${plan.tasks.length - 10} more\n`));
|
|
964
1002
|
}
|
|
965
1003
|
}
|
|
966
1004
|
if (Array.isArray(plan.notes) && plan.notes.length > 0) {
|
|
967
1005
|
for (const note of plan.notes.slice(0, 3)) {
|
|
968
|
-
process.
|
|
1006
|
+
process.stdout.write(chalk.gray(` note: ${this.fitTerminalText(this.sanitizeServerPath(String(note)), 12)}\n`));
|
|
969
1007
|
}
|
|
970
1008
|
}
|
|
971
1009
|
if (Array.isArray(plan.target_files) && plan.target_files.length > 0) {
|
|
972
|
-
process.
|
|
1010
|
+
process.stdout.write(chalk.gray(` ${this.fitTerminalText(`Files: ${plan.target_files.map((filePath) => this.sanitizeServerPath(String(filePath))).join(', ')}`, 6)}\n`));
|
|
973
1011
|
}
|
|
974
|
-
spinner.start();
|
|
975
1012
|
spinner.text = status === 'planning' ? 'Planning...' : 'Executing plan...';
|
|
976
1013
|
return;
|
|
977
1014
|
}
|
|
@@ -1194,7 +1231,7 @@ export class ChatCommand {
|
|
|
1194
1231
|
if (sessionConfig.debugMode) {
|
|
1195
1232
|
process.env.DEBUG = process.env.DEBUG || 'vigthoria:*';
|
|
1196
1233
|
}
|
|
1197
|
-
console.log(chalk.green(`Using workspace: ${this.currentProjectPath}`));
|
|
1234
|
+
console.log(chalk.green(this.fitTerminalText(`Using workspace: ${this.currentProjectPath}`)));
|
|
1198
1235
|
}
|
|
1199
1236
|
if (this.jsonOutput && !options.prompt && !options.retry && !options.continue) {
|
|
1200
1237
|
throw new Error('--json is only supported together with --prompt, --retry, or --continue.');
|
|
@@ -2508,11 +2545,14 @@ export class ChatCommand {
|
|
|
2508
2545
|
this.v3LastActivity = Date.now();
|
|
2509
2546
|
this.v3StreamingStarted = false;
|
|
2510
2547
|
this.v3StreamedAnswerBuffer = '';
|
|
2511
|
-
|
|
2548
|
+
this.v3SeenToolCalls.clear();
|
|
2549
|
+
this.v3SeenToolResults.clear();
|
|
2550
|
+
const taskDisplay = new TaskDisplay(['Analyse workspace', 'Execute tasks', 'Validate output', 'Self-heal'], false);
|
|
2512
2551
|
taskDisplay.start(0);
|
|
2513
2552
|
const spinner = this.jsonOutput ? null : createSpinner({
|
|
2514
2553
|
text: routingPolicy.cloudSelected ? 'Routing heavy task to Vigthoria Cloud...' : 'Routing to V3 Agent...',
|
|
2515
2554
|
spinner: 'clock',
|
|
2555
|
+
isSilent: true,
|
|
2516
2556
|
}).start();
|
|
2517
2557
|
// Live run telemetry, used both for the final summary block and for /retry, /continue.
|
|
2518
2558
|
const liveOutcome = {
|
|
@@ -3105,10 +3145,10 @@ export class ChatCommand {
|
|
|
3105
3145
|
? 'Interactive Agent Chat'
|
|
3106
3146
|
: 'Interactive Chat';
|
|
3107
3147
|
this.logger.section(this.workflowTarget ? `${chatTitle} Via Workflow Target` : chatTitle);
|
|
3108
|
-
console.log(chalk.gray('Type /help for commands. Type /exit to quit.'));
|
|
3109
|
-
console.log(chalk.gray('Multi-line: end a line with \\ or start a block with {{{ and end with }}}'));
|
|
3148
|
+
console.log(chalk.gray(this.fitTerminalText('Type /help for commands. Type /exit to quit.')));
|
|
3149
|
+
console.log(chalk.gray(this.fitTerminalText('Multi-line: end a line with \\ or start a block with {{{ and end with }}}')));
|
|
3110
3150
|
if (this.workflowTarget) {
|
|
3111
|
-
console.log(chalk.gray(`Workflow target: ${this.workflowTarget}`));
|
|
3151
|
+
console.log(chalk.gray(this.fitTerminalText(`Workflow target: ${this.workflowTarget}`)));
|
|
3112
3152
|
}
|
|
3113
3153
|
const rl = readline.createInterface({
|
|
3114
3154
|
input: process.stdin,
|
package/dist/index.js
CHANGED
|
@@ -567,22 +567,34 @@ export async function main(args) {
|
|
|
567
567
|
return;
|
|
568
568
|
}
|
|
569
569
|
}
|
|
570
|
-
// Banner - Fixed alignment with proper padding
|
|
571
|
-
const boxWidth = 61; // Inner content width
|
|
572
|
-
const titleText = 'VIGTHORIA CLI - AI-Powered Coding Assistant';
|
|
573
|
-
const versionText = `Version ${VERSION}`;
|
|
574
|
-
// Calculate padding for centering
|
|
575
|
-
const titlePad = Math.floor((boxWidth - 4 - titleText.length) / 2);
|
|
576
|
-
const versionPad = Math.floor((boxWidth - 4 - versionText.length) / 2);
|
|
577
570
|
if (process.env.VIGTHORIA_NO_BANNER !== '1' &&
|
|
578
571
|
!jsonOutputRequested &&
|
|
579
572
|
!directPromptRequested &&
|
|
580
573
|
!helpOrVersionRequested) {
|
|
574
|
+
const terminalWidth = Math.max(36, Number(process.stdout.columns || 80));
|
|
575
|
+
const boxWidth = Math.max(34, Math.min(61, terminalWidth - 2));
|
|
576
|
+
const innerWidth = boxWidth;
|
|
577
|
+
const fit = (text) => {
|
|
578
|
+
const clean = String(text || '').replace(/\s+/g, ' ').trim();
|
|
579
|
+
return clean.length > innerWidth ? `${clean.slice(0, Math.max(1, innerWidth - 1))}…` : clean;
|
|
580
|
+
};
|
|
581
|
+
const center = (text, colour = (value) => value) => {
|
|
582
|
+
const fitted = fit(text);
|
|
583
|
+
const left = Math.max(0, Math.floor((innerWidth - fitted.length) / 2));
|
|
584
|
+
const right = Math.max(0, innerWidth - fitted.length - left);
|
|
585
|
+
return chalk.cyan(CH.dV) + ' '.repeat(left) + colour(fitted) + ' '.repeat(right) + chalk.cyan(CH.dV);
|
|
586
|
+
};
|
|
587
|
+
const titleLine = boxWidth < 48 ? 'VIGTHORIA CLI' : 'VIGTHORIA CLI - AI Coding Assistant';
|
|
588
|
+
const subtitleLine = boxWidth < 48 ? 'AI Coding Assistant' : `Version ${VERSION}`;
|
|
589
|
+
const versionLine = boxWidth < 48 ? `Version ${VERSION}` : '';
|
|
581
590
|
console.log(chalk.cyan(CH.dTl + CH.dH.repeat(boxWidth) + CH.dTr));
|
|
582
|
-
console.log(
|
|
583
|
-
console.log(
|
|
584
|
-
console.log(
|
|
585
|
-
|
|
591
|
+
console.log(center(''));
|
|
592
|
+
console.log(center(titleLine, (value) => chalk.bold.white(value)));
|
|
593
|
+
console.log(center(subtitleLine, (value) => chalk.gray(value)));
|
|
594
|
+
if (versionLine) {
|
|
595
|
+
console.log(center(versionLine, (value) => chalk.gray(value)));
|
|
596
|
+
}
|
|
597
|
+
console.log(center(''));
|
|
586
598
|
console.log(chalk.cyan(CH.dBl + CH.dH.repeat(boxWidth) + CH.dBr));
|
|
587
599
|
console.log();
|
|
588
600
|
}
|
|
@@ -30,11 +30,35 @@ const LIST_ONLY_DISCOVERY_TOOLS = new Set([
|
|
|
30
30
|
'dir',
|
|
31
31
|
]);
|
|
32
32
|
const GENERIC_SUMMARY_RE = /^(completed the requested analysis|reviewed the workspace without writing changes|task completed|done|finished|analysis completed)([.\s]|$)/i;
|
|
33
|
+
function looksLikeRawV3EventPayload(text) {
|
|
34
|
+
const trimmed = String(text || '').trim();
|
|
35
|
+
if (!/^[{[]/.test(trimmed))
|
|
36
|
+
return false;
|
|
37
|
+
try {
|
|
38
|
+
const parsed = JSON.parse(trimmed);
|
|
39
|
+
const root = Array.isArray(parsed) ? { events: parsed } : parsed;
|
|
40
|
+
if (!root || typeof root !== 'object')
|
|
41
|
+
return false;
|
|
42
|
+
if (Array.isArray(root.events) && root.events.some((event) => event && typeof event === 'object' && typeof event.type === 'string')) {
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
45
|
+
return Boolean(root.context_id
|
|
46
|
+
|| root.mcp_context_id
|
|
47
|
+
|| root.workspace_uri
|
|
48
|
+
|| root.execution_surface
|
|
49
|
+
|| root.task_id);
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
33
55
|
/** Tool-trace stubs like `[read_file] "index.html"` or `<read_file>…</read_file>` — not a user-facing answer. */
|
|
34
56
|
export function isToolEvidenceStubAnswer(text) {
|
|
35
57
|
const trimmed = String(text || '').trim();
|
|
36
58
|
if (!trimmed)
|
|
37
59
|
return true;
|
|
60
|
+
if (looksLikeRawV3EventPayload(trimmed))
|
|
61
|
+
return true;
|
|
38
62
|
if (BOOTSTRAP_PLACEHOLDER_RE.test(trimmed))
|
|
39
63
|
return true;
|
|
40
64
|
if (GENERIC_SUMMARY_RE.test(trimmed.replace(/\.\s*\d+\s+tool steps.*$/i, '').trim()))
|
package/dist/utils/api.js
CHANGED
|
@@ -3380,8 +3380,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
3380
3380
|
const fileList = Object.keys(data.files).join(', ');
|
|
3381
3381
|
return `Agent wrote workspace files: ${sanitizeUserFacingPathText(fileList)}`;
|
|
3382
3382
|
}
|
|
3383
|
-
|
|
3384
|
-
return text.length > 12000 ? `${text.slice(0, 12000)}\n\n[V3 agent output truncated]` : text;
|
|
3383
|
+
return '';
|
|
3385
3384
|
}
|
|
3386
3385
|
sanitizeV3AgentResponseText(input) {
|
|
3387
3386
|
let text = sanitizeUserFacingPathText(String(input || ''));
|
package/dist/utils/logger.js
CHANGED
|
@@ -162,8 +162,13 @@ export class Logger {
|
|
|
162
162
|
}
|
|
163
163
|
// Section header
|
|
164
164
|
section(title) {
|
|
165
|
+
const width = Math.max(24, Number(process.stdout.columns || 80));
|
|
166
|
+
const cleanTitle = String(title || '').replace(/\s+/g, ' ').trim();
|
|
167
|
+
const maxTitle = Math.max(10, width - 10);
|
|
168
|
+
const fittedTitle = cleanTitle.length > maxTitle ? `${cleanTitle.slice(0, maxTitle - 1)}…` : cleanTitle;
|
|
169
|
+
const side = Math.max(3, Math.floor((Math.min(width, 72) - fittedTitle.length - 2) / 2));
|
|
165
170
|
console.log();
|
|
166
|
-
console.log(chalk.bold.cyan(`${CH.hDouble.repeat(
|
|
171
|
+
console.log(chalk.bold.cyan(`${CH.hDouble.repeat(side)} ${fittedTitle} ${CH.hDouble.repeat(side)}`));
|
|
167
172
|
console.log();
|
|
168
173
|
}
|
|
169
174
|
// Progress
|