vigthoria-cli 1.6.20 → 1.6.22
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 +8 -0
- package/dist/commands/chat.js +129 -12
- package/dist/commands/deploy.js +16 -8
- package/dist/commands/edit.js +22 -5
- package/dist/commands/generate.d.ts +5 -0
- package/dist/commands/generate.js +30 -7
- package/dist/commands/repo.js +14 -7
- package/dist/index.js +9 -1
- package/dist/utils/api.d.ts +12 -0
- package/dist/utils/api.js +161 -27
- package/dist/utils/bridge-client.d.ts +110 -0
- package/dist/utils/bridge-client.js +278 -0
- package/dist/utils/logger.d.ts +9 -1
- package/dist/utils/logger.js +13 -2
- package/dist/utils/tools.js +4 -0
- package/package.json +2 -1
package/dist/commands/chat.d.ts
CHANGED
|
@@ -15,6 +15,7 @@ interface ChatOptions {
|
|
|
15
15
|
stream?: boolean;
|
|
16
16
|
prompt?: string;
|
|
17
17
|
json?: boolean;
|
|
18
|
+
bridge?: string;
|
|
18
19
|
}
|
|
19
20
|
export declare class ChatCommand {
|
|
20
21
|
private config;
|
|
@@ -46,6 +47,11 @@ export declare class ChatCommand {
|
|
|
46
47
|
private resolveAgentExecutionPolicy;
|
|
47
48
|
private getMessagesForModel;
|
|
48
49
|
private isDiagnosticPrompt;
|
|
50
|
+
/**
|
|
51
|
+
* Returns true when the prompt is a simple lookup / analysis / read-only
|
|
52
|
+
* question — these should use analysis_only workflow, not full_autonomy.
|
|
53
|
+
*/
|
|
54
|
+
private isAnalysisLookupPrompt;
|
|
49
55
|
private isBrowserTaskPrompt;
|
|
50
56
|
private inferAgentTaskType;
|
|
51
57
|
private buildTaskShapingInstructions;
|
|
@@ -59,6 +65,8 @@ export declare class ChatCommand {
|
|
|
59
65
|
private updateOperatorSpinner;
|
|
60
66
|
constructor(config: Config, logger: Logger);
|
|
61
67
|
run(options: ChatOptions): Promise<void>;
|
|
68
|
+
/** Handle an inbound admin command from the Commando Bridge. */
|
|
69
|
+
private handleAdminCommand;
|
|
62
70
|
private ensureProjectWorkspace;
|
|
63
71
|
private resolveProjectPath;
|
|
64
72
|
private shouldUseManagedWorkspace;
|
package/dist/commands/chat.js
CHANGED
|
@@ -46,6 +46,7 @@ const logger_js_1 = require("../utils/logger.js");
|
|
|
46
46
|
const api_js_1 = require("../utils/api.js");
|
|
47
47
|
const tools_js_1 = require("../utils/tools.js");
|
|
48
48
|
const session_js_1 = require("../utils/session.js");
|
|
49
|
+
const bridge_client_js_1 = require("../utils/bridge-client.js");
|
|
49
50
|
const DEFAULT_V3_AGENT_TIMEOUT_MS = (() => {
|
|
50
51
|
const rawValue = process.env.VIGTHORIA_AGENT_TIMEOUT_MS || process.env.V3_AGENT_TIMEOUT_MS || '3900000';
|
|
51
52
|
const parsed = Number.parseInt(rawValue, 10);
|
|
@@ -195,6 +196,13 @@ class ChatCommand {
|
|
|
195
196
|
isDiagnosticPrompt(prompt) {
|
|
196
197
|
return /(startup|start up|won'?t start|doesn'?t start|crash|crashes|error|errors|failing|fails|issue|issues|bug|bugs|diagnos|debug|runtime|log|logs|exception|traceback|stack trace|yaml|blocking|blocker)/i.test(prompt);
|
|
197
198
|
}
|
|
199
|
+
/**
|
|
200
|
+
* Returns true when the prompt is a simple lookup / analysis / read-only
|
|
201
|
+
* question — these should use analysis_only workflow, not full_autonomy.
|
|
202
|
+
*/
|
|
203
|
+
isAnalysisLookupPrompt(prompt) {
|
|
204
|
+
return /^(what|which|where|how many|who|find|list|show|check|inspect|analyze|analyse|audit|explain|describe|summarize|summarise|review|overview|count|read|look at|tell me|locate|search for|does .* exist)/i.test(prompt.trim());
|
|
205
|
+
}
|
|
198
206
|
isBrowserTaskPrompt(prompt) {
|
|
199
207
|
return /(browser|chrome|devtools|console|dom|network tab|network request|frontend runtime|client-side|client side|rendering|page load|websocket|ui bug|inspect element)/i.test(prompt);
|
|
200
208
|
}
|
|
@@ -360,7 +368,13 @@ class ChatCommand {
|
|
|
360
368
|
}
|
|
361
369
|
async run(options) {
|
|
362
370
|
if (!this.config.isAuthenticated()) {
|
|
363
|
-
|
|
371
|
+
if (options.json) {
|
|
372
|
+
process.exitCode = 1;
|
|
373
|
+
console.log(JSON.stringify({ success: false, error: 'Not authenticated. Run: vigthoria login' }, null, 2));
|
|
374
|
+
}
|
|
375
|
+
else {
|
|
376
|
+
this.logger.error('Not authenticated. Run: vigthoria login');
|
|
377
|
+
}
|
|
364
378
|
return;
|
|
365
379
|
}
|
|
366
380
|
this.agentMode = options.agent === true;
|
|
@@ -382,6 +396,21 @@ class ChatCommand {
|
|
|
382
396
|
this.directToolContinuationCount = 0;
|
|
383
397
|
this.tools = new tools_js_1.AgenticTools(this.logger, this.currentProjectPath, async (action) => this.requestPermission(action), this.autoApprove);
|
|
384
398
|
this.initializeSession(options.resume === true);
|
|
399
|
+
// ── Commando Bridge: connect if --bridge was specified ──────────
|
|
400
|
+
if (options.bridge) {
|
|
401
|
+
const bridgeClient = new bridge_client_js_1.BridgeClient({
|
|
402
|
+
bridgeUrl: options.bridge,
|
|
403
|
+
apiKey: this.config.get('authToken'),
|
|
404
|
+
onAdminCommand: (cmd) => this.handleAdminCommand(cmd),
|
|
405
|
+
});
|
|
406
|
+
await bridgeClient.connect();
|
|
407
|
+
const mode = this.operatorMode ? 'operator' : this.agentMode ? 'agent' : 'chat';
|
|
408
|
+
bridgeClient.emitStart({
|
|
409
|
+
command: mode,
|
|
410
|
+
flags: { model: this.currentModel, agent: this.agentMode, operator: this.operatorMode, autoApprove: this.autoApprove },
|
|
411
|
+
cwd: this.currentProjectPath,
|
|
412
|
+
});
|
|
413
|
+
}
|
|
385
414
|
if (this.operatorMode && !this.hasOperatorAccess()) {
|
|
386
415
|
if (this.currentSession) {
|
|
387
416
|
this.currentSession.operatorMode = false;
|
|
@@ -393,9 +422,35 @@ class ChatCommand {
|
|
|
393
422
|
}
|
|
394
423
|
if (options.prompt) {
|
|
395
424
|
await this.handleDirectPrompt(options.prompt);
|
|
425
|
+
(0, bridge_client_js_1.getBridgeClient)()?.emitEnd({ reason: 'prompt-complete' });
|
|
396
426
|
return;
|
|
397
427
|
}
|
|
398
428
|
await this.startInteractiveChat();
|
|
429
|
+
(0, bridge_client_js_1.getBridgeClient)()?.emitEnd({ reason: 'interactive-exit' });
|
|
430
|
+
}
|
|
431
|
+
/** Handle an inbound admin command from the Commando Bridge. */
|
|
432
|
+
handleAdminCommand(cmd) {
|
|
433
|
+
switch (cmd.action) {
|
|
434
|
+
case 'ping':
|
|
435
|
+
(0, bridge_client_js_1.getBridgeClient)()?.emitModelResponse({ model: this.currentModel, chars: 0, hasToolCalls: false, preview: 'pong' });
|
|
436
|
+
break;
|
|
437
|
+
case 'set-model':
|
|
438
|
+
if (cmd.params?.value && typeof cmd.params.value === 'string') {
|
|
439
|
+
this.currentModel = cmd.params.value;
|
|
440
|
+
(0, bridge_client_js_1.getBridgeClient)()?.emitModeChange({ mode: this.operatorMode ? 'operator' : this.agentMode ? 'agent' : 'chat', model: this.currentModel });
|
|
441
|
+
if (!this.jsonOutput)
|
|
442
|
+
console.log(chalk_1.default.yellow(`[bridge] Model changed to: ${this.currentModel}`));
|
|
443
|
+
}
|
|
444
|
+
break;
|
|
445
|
+
case 'abort':
|
|
446
|
+
if (!this.jsonOutput)
|
|
447
|
+
console.log(chalk_1.default.red(`[bridge] Abort requested by admin`));
|
|
448
|
+
(0, bridge_client_js_1.getBridgeClient)()?.emitEnd({ reason: 'admin-abort' });
|
|
449
|
+
process.exit(0);
|
|
450
|
+
break;
|
|
451
|
+
default:
|
|
452
|
+
(0, bridge_client_js_1.getBridgeClient)()?.emitError({ message: `Unknown admin command: ${cmd.action}` });
|
|
453
|
+
}
|
|
399
454
|
}
|
|
400
455
|
ensureProjectWorkspace() {
|
|
401
456
|
if (fs.existsSync(this.currentProjectPath)) {
|
|
@@ -611,7 +666,8 @@ class ChatCommand {
|
|
|
611
666
|
}
|
|
612
667
|
catch (error) {
|
|
613
668
|
if (spinner) {
|
|
614
|
-
spinner.
|
|
669
|
+
spinner.stop();
|
|
670
|
+
this.logger.error('Workflow target execution failed');
|
|
615
671
|
}
|
|
616
672
|
throw error;
|
|
617
673
|
}
|
|
@@ -621,10 +677,37 @@ class ChatCommand {
|
|
|
621
677
|
this.logger.error(this.operatorAccessMessage());
|
|
622
678
|
return;
|
|
623
679
|
}
|
|
680
|
+
(0, bridge_client_js_1.getBridgeClient)()?.emitPrompt({ prompt, mode: 'operator', model: this.currentModel });
|
|
624
681
|
const runtimeContext = await this.getPromptRuntimeContext(prompt);
|
|
625
682
|
const spinner = this.jsonOutput ? null : (0, logger_js_1.createSpinner)({ text: 'Thinking like an operator...', spinner: 'clock' }).start();
|
|
626
|
-
const
|
|
627
|
-
const workflowType = this.isDiagnosticPrompt(prompt)
|
|
683
|
+
const isLookup = this.isAnalysisLookupPrompt(prompt);
|
|
684
|
+
const workflowType = this.isDiagnosticPrompt(prompt) || isLookup
|
|
685
|
+
? 'analysis_only'
|
|
686
|
+
: 'full_autonomy';
|
|
687
|
+
// For lightweight lookup tasks, prepend a grounding constraint so
|
|
688
|
+
// the operator returns a concise answer rather than a verbose report.
|
|
689
|
+
let executionPrompt = this.buildExecutionPrompt(prompt);
|
|
690
|
+
if (isLookup) {
|
|
691
|
+
// Inject workspace file listing into the prompt so the operator
|
|
692
|
+
// can answer "which file defines X" without a full agent loop.
|
|
693
|
+
let fileListing = '';
|
|
694
|
+
try {
|
|
695
|
+
const snapshot = this.api.getAgentWorkspaceSnapshot(this.currentProjectPath);
|
|
696
|
+
if (snapshot && snapshot.paths.length > 0) {
|
|
697
|
+
fileListing = '\n\nWorkspace file listing:\n' + snapshot.paths.slice(0, 80).join('\n');
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
catch { /* ignore */ }
|
|
701
|
+
executionPrompt = [
|
|
702
|
+
'INSTRUCTION: This is a lightweight lookup task. Return ONLY the concise answer the user asked for.',
|
|
703
|
+
'Do NOT produce a certification report, audit, or analysis blob.',
|
|
704
|
+
'Do NOT return files_analyzed counts or summary statistics.',
|
|
705
|
+
'Just answer the question directly.',
|
|
706
|
+
fileListing,
|
|
707
|
+
'',
|
|
708
|
+
executionPrompt,
|
|
709
|
+
].join('\n');
|
|
710
|
+
}
|
|
628
711
|
try {
|
|
629
712
|
const response = await this.api.runOperatorWorkflow(executionPrompt, {
|
|
630
713
|
workspacePath: this.currentProjectPath,
|
|
@@ -665,9 +748,12 @@ class ChatCommand {
|
|
|
665
748
|
}
|
|
666
749
|
catch (error) {
|
|
667
750
|
if (spinner) {
|
|
668
|
-
spinner.
|
|
751
|
+
spinner.stop();
|
|
669
752
|
}
|
|
670
753
|
const errorMsg = error.message || 'Operator workflow failed with an unknown error.';
|
|
754
|
+
if (!this.jsonOutput) {
|
|
755
|
+
this.logger.error('Operator workflow failed');
|
|
756
|
+
}
|
|
671
757
|
if (this.jsonOutput) {
|
|
672
758
|
process.exitCode = 1;
|
|
673
759
|
console.log(JSON.stringify({
|
|
@@ -686,14 +772,30 @@ class ChatCommand {
|
|
|
686
772
|
this.lastActionableUserInput = prompt;
|
|
687
773
|
// In non-agent chat mode the model has no tool access. Inject a
|
|
688
774
|
// grounding constraint so it doesn't fabricate file contents.
|
|
775
|
+
// Also inject a real file listing so the model can reference actual
|
|
776
|
+
// paths instead of guessing.
|
|
689
777
|
const needsGrounding = /(repo|file|code|project|workspace|source|inspect|analyze|audit|review)/i.test(prompt);
|
|
690
778
|
if (needsGrounding && !this.messages.some(m => m.role === 'system' && m.content.includes('no direct file access'))) {
|
|
779
|
+
let groundingContent = 'You are in simple chat mode with no direct file access or tools. Do not fabricate file contents, search results, or analysis steps. If the user asks you to modify, edit, or deeply inspect files, advise them to use agent mode (vig chat --agent) for grounded repo analysis.';
|
|
780
|
+
// Inject a workspace file listing so the model has real paths
|
|
781
|
+
try {
|
|
782
|
+
const snapshot = this.api.getAgentWorkspaceSnapshot(this.currentProjectPath);
|
|
783
|
+
if (snapshot && snapshot.paths.length > 0) {
|
|
784
|
+
const listing = snapshot.paths.slice(0, 60).join('\n');
|
|
785
|
+
groundingContent += `\n\nWorkspace: ${this.currentProjectPath}\nFile listing (${snapshot.fileCount} files total):\n${listing}`;
|
|
786
|
+
if (snapshot.fileCount > 60) {
|
|
787
|
+
groundingContent += `\n... and ${snapshot.fileCount - 60} more files.`;
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
catch { /* ignore snapshot errors */ }
|
|
691
792
|
this.messages.push({
|
|
692
793
|
role: 'system',
|
|
693
|
-
content:
|
|
794
|
+
content: groundingContent,
|
|
694
795
|
});
|
|
695
796
|
}
|
|
696
797
|
this.messages.push({ role: 'user', content: this.buildExecutionPrompt(prompt) });
|
|
798
|
+
(0, bridge_client_js_1.getBridgeClient)()?.emitPrompt({ prompt, mode: 'chat', model: this.currentModel });
|
|
697
799
|
const spinner = this.jsonOutput ? null : (0, logger_js_1.createSpinner)({ text: 'Thinking...', spinner: 'clock' }).start();
|
|
698
800
|
try {
|
|
699
801
|
const response = await this.api.chat(this.getMessagesForModel(), this.currentModel);
|
|
@@ -719,7 +821,9 @@ class ChatCommand {
|
|
|
719
821
|
}
|
|
720
822
|
catch (error) {
|
|
721
823
|
if (spinner)
|
|
722
|
-
spinner.
|
|
824
|
+
spinner.stop();
|
|
825
|
+
if (!this.jsonOutput)
|
|
826
|
+
this.logger.error('Failed to get response');
|
|
723
827
|
const errorMsg = error.message;
|
|
724
828
|
if (this.jsonOutput) {
|
|
725
829
|
process.exitCode = 1;
|
|
@@ -772,6 +876,7 @@ class ChatCommand {
|
|
|
772
876
|
this.directToolContinuationCount = 0;
|
|
773
877
|
this.agentToolEvidence = { discovery: 0, mutation: 0, searchFailed: 0 };
|
|
774
878
|
this.tools.clearSessionApprovals();
|
|
879
|
+
(0, bridge_client_js_1.getBridgeClient)()?.emitPrompt({ prompt, mode: this.operatorMode ? 'operator' : 'agent', model: this.currentModel });
|
|
775
880
|
this.ensureAgentSystemPrompt();
|
|
776
881
|
this.messages.push({ role: 'user', content: this.buildScopedUserPrompt(prompt) });
|
|
777
882
|
this.saveSession();
|
|
@@ -786,6 +891,12 @@ class ChatCommand {
|
|
|
786
891
|
this.messages.push({ role: 'assistant', content: assistantMessage });
|
|
787
892
|
const toolCalls = this.extractToolCalls(assistantMessage);
|
|
788
893
|
const visibleText = this.stripToolPayloads(assistantMessage).trim();
|
|
894
|
+
(0, bridge_client_js_1.getBridgeClient)()?.emitModelResponse({
|
|
895
|
+
model: this.currentModel,
|
|
896
|
+
chars: assistantMessage.length,
|
|
897
|
+
hasToolCalls: toolCalls.length > 0,
|
|
898
|
+
preview: visibleText.slice(0, 300),
|
|
899
|
+
});
|
|
789
900
|
if (toolCalls.length === 0) {
|
|
790
901
|
// Phase 5: Quality gate — if the agent tries to conclude on the first
|
|
791
902
|
// turn without any discovery, push it to gather evidence first.
|
|
@@ -830,7 +941,9 @@ class ChatCommand {
|
|
|
830
941
|
}
|
|
831
942
|
catch (error) {
|
|
832
943
|
if (spinner)
|
|
833
|
-
spinner.
|
|
944
|
+
spinner.stop();
|
|
945
|
+
if (!this.jsonOutput)
|
|
946
|
+
this.logger.error('Agent request failed');
|
|
834
947
|
if (this.jsonOutput) {
|
|
835
948
|
process.exitCode = 1;
|
|
836
949
|
console.log(JSON.stringify({
|
|
@@ -1040,14 +1153,15 @@ class ChatCommand {
|
|
|
1040
1153
|
if (!success) {
|
|
1041
1154
|
if (this.isLegacyAgentFallbackAllowed()) {
|
|
1042
1155
|
if (spinner) {
|
|
1043
|
-
spinner.
|
|
1156
|
+
spinner.stop();
|
|
1044
1157
|
}
|
|
1158
|
+
this.logger.warn('Falling back to legacy CLI agent loop');
|
|
1045
1159
|
this.logger.debug(`V3 agent workflow returned an incomplete result: ${previewGate?.error || 'workspace changes were not fully validated'}`);
|
|
1046
1160
|
return false;
|
|
1047
1161
|
}
|
|
1048
1162
|
const errorMessage = `V3 agent workflow returned an incomplete result and legacy fallback is disabled. ${previewGate?.error || 'Workspace changes were not fully validated.'}`;
|
|
1049
1163
|
if (spinner) {
|
|
1050
|
-
spinner.
|
|
1164
|
+
spinner.stop();
|
|
1051
1165
|
}
|
|
1052
1166
|
this.logger.error(errorMessage);
|
|
1053
1167
|
this.messages.push({ role: 'assistant', content: errorMessage });
|
|
@@ -1109,13 +1223,14 @@ class ChatCommand {
|
|
|
1109
1223
|
}
|
|
1110
1224
|
if (this.isLegacyAgentFallbackAllowed()) {
|
|
1111
1225
|
if (spinner) {
|
|
1112
|
-
spinner.
|
|
1226
|
+
spinner.stop();
|
|
1113
1227
|
}
|
|
1228
|
+
this.logger.warn('Falling back to legacy CLI agent loop');
|
|
1114
1229
|
this.logger.debug(`V3 agent workflow unavailable: ${error.message}`);
|
|
1115
1230
|
return false;
|
|
1116
1231
|
}
|
|
1117
1232
|
if (spinner) {
|
|
1118
|
-
spinner.
|
|
1233
|
+
spinner.stop();
|
|
1119
1234
|
}
|
|
1120
1235
|
const errorMessage = `Agent mode requires the V3 workflow and will not fall back to the legacy CLI loop. ${error.message}`;
|
|
1121
1236
|
this.logger.error(errorMessage);
|
|
@@ -1718,6 +1833,7 @@ class ChatCommand {
|
|
|
1718
1833
|
if (!this.jsonOutput) {
|
|
1719
1834
|
console.log(chalk_1.default.cyan(`⚙ Executing: ${call.tool}`));
|
|
1720
1835
|
}
|
|
1836
|
+
(0, bridge_client_js_1.getBridgeClient)()?.emitToolCall({ tool: call.tool, args: call.args });
|
|
1721
1837
|
let result = await this.tools.execute(call);
|
|
1722
1838
|
// Phase 2: If a search tool failed (search_failed), retry with alternate approach
|
|
1723
1839
|
const searchStatus = result.metadata?.searchStatus;
|
|
@@ -1739,6 +1855,7 @@ class ChatCommand {
|
|
|
1739
1855
|
console.log(result.success ? chalk_1.default.gray(summary) : chalk_1.default.red(summary));
|
|
1740
1856
|
}
|
|
1741
1857
|
this.messages.push({ role: 'system', content: summary });
|
|
1858
|
+
(0, bridge_client_js_1.getBridgeClient)()?.emitToolResult({ tool: call.tool, success: result.success, preview: (result.output || result.error || '').slice(0, 300) });
|
|
1742
1859
|
// Phase 5: Track tool evidence for quality gates
|
|
1743
1860
|
const finalStatus = result.metadata?.searchStatus;
|
|
1744
1861
|
if (finalStatus === 'search_failed') {
|
package/dist/commands/deploy.js
CHANGED
|
@@ -151,7 +151,8 @@ class DeployCommand {
|
|
|
151
151
|
console.log(chalk_1.default.gray(' Upgrade to a subdomain for permanent hosting.\n'));
|
|
152
152
|
}
|
|
153
153
|
catch (error) {
|
|
154
|
-
spinner.
|
|
154
|
+
spinner.stop();
|
|
155
|
+
this.logger.error('Deploy failed');
|
|
155
156
|
const errMsg = error instanceof Error ? error.message : 'Unknown error';
|
|
156
157
|
console.log(chalk_1.default.red(`\n❌ Error: ${errMsg}\n`));
|
|
157
158
|
}
|
|
@@ -204,7 +205,8 @@ class DeployCommand {
|
|
|
204
205
|
console.log(chalk_1.default.gray(' ✓ Unlimited traffic included\n'));
|
|
205
206
|
}
|
|
206
207
|
catch (error) {
|
|
207
|
-
spinner.
|
|
208
|
+
spinner.stop();
|
|
209
|
+
this.logger.error('Deploy failed');
|
|
208
210
|
const errMsg = error instanceof Error ? error.message : 'Unknown error';
|
|
209
211
|
console.log(chalk_1.default.red(`\n❌ Error: ${errMsg}\n`));
|
|
210
212
|
}
|
|
@@ -258,7 +260,8 @@ class DeployCommand {
|
|
|
258
260
|
}
|
|
259
261
|
}
|
|
260
262
|
catch (error) {
|
|
261
|
-
spinner.
|
|
263
|
+
spinner.stop();
|
|
264
|
+
this.logger.error('Deploy failed');
|
|
262
265
|
const errMsg = error instanceof Error ? error.message : 'Unknown error';
|
|
263
266
|
console.log(chalk_1.default.red(`\n❌ Error: ${errMsg}\n`));
|
|
264
267
|
}
|
|
@@ -334,7 +337,8 @@ class DeployCommand {
|
|
|
334
337
|
console.log(chalk_1.default.cyan('\n Subscribe: vig deploy --subdomain myapp\n'));
|
|
335
338
|
}
|
|
336
339
|
catch (error) {
|
|
337
|
-
spinner.
|
|
340
|
+
spinner.stop();
|
|
341
|
+
this.logger.error('Failed to fetch plans');
|
|
338
342
|
const errMsg = error instanceof Error ? error.message : 'Unknown error';
|
|
339
343
|
console.log(chalk_1.default.red(`\n❌ Error: ${errMsg}\n`));
|
|
340
344
|
}
|
|
@@ -374,7 +378,8 @@ class DeployCommand {
|
|
|
374
378
|
}
|
|
375
379
|
}
|
|
376
380
|
catch (error) {
|
|
377
|
-
spinner.
|
|
381
|
+
spinner.stop();
|
|
382
|
+
this.logger.error('List failed');
|
|
378
383
|
const errMsg = error instanceof Error ? error.message : 'Unknown error';
|
|
379
384
|
console.log(chalk_1.default.red(`\n❌ Error: ${errMsg}\n`));
|
|
380
385
|
}
|
|
@@ -401,7 +406,8 @@ class DeployCommand {
|
|
|
401
406
|
console.log(JSON.stringify(data, null, 2));
|
|
402
407
|
}
|
|
403
408
|
catch (error) {
|
|
404
|
-
spinner.
|
|
409
|
+
spinner.stop();
|
|
410
|
+
this.logger.error('Status check failed');
|
|
405
411
|
const errMsg = error instanceof Error ? error.message : 'Unknown error';
|
|
406
412
|
console.log(chalk_1.default.red(`\n❌ Error: ${errMsg}\n`));
|
|
407
413
|
}
|
|
@@ -434,7 +440,8 @@ class DeployCommand {
|
|
|
434
440
|
}
|
|
435
441
|
}
|
|
436
442
|
catch (error) {
|
|
437
|
-
spinner.
|
|
443
|
+
spinner.stop();
|
|
444
|
+
this.logger.error('Verification failed');
|
|
438
445
|
const errMsg = error instanceof Error ? error.message : 'Unknown error';
|
|
439
446
|
console.log(chalk_1.default.red(`\n❌ Error: ${errMsg}\n`));
|
|
440
447
|
}
|
|
@@ -468,7 +475,8 @@ class DeployCommand {
|
|
|
468
475
|
console.log(chalk_1.default.gray('\n Your project files are still in your repository.\n'));
|
|
469
476
|
}
|
|
470
477
|
catch (error) {
|
|
471
|
-
spinner.
|
|
478
|
+
spinner.stop();
|
|
479
|
+
this.logger.error('Remove failed');
|
|
472
480
|
const errMsg = error instanceof Error ? error.message : 'Unknown error';
|
|
473
481
|
console.log(chalk_1.default.red(`\n❌ Error: ${errMsg}\n`));
|
|
474
482
|
}
|
package/dist/commands/edit.js
CHANGED
|
@@ -41,6 +41,11 @@ class EditCommand {
|
|
|
41
41
|
// Get instruction
|
|
42
42
|
let instruction = options.instruction;
|
|
43
43
|
if (!instruction) {
|
|
44
|
+
// --apply requires --instruction to avoid hanging on non-interactive terminals
|
|
45
|
+
if (options.apply) {
|
|
46
|
+
this.logger.error('The --apply flag requires --instruction. Example: vigthoria edit file.ts --apply --instruction "fix the bug"');
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
44
49
|
const answer = await inquirer_1.default.prompt([
|
|
45
50
|
{
|
|
46
51
|
type: 'input',
|
|
@@ -60,9 +65,16 @@ class EditCommand {
|
|
|
60
65
|
const response = await this.api.chat([
|
|
61
66
|
{
|
|
62
67
|
role: 'system',
|
|
63
|
-
content: `You are a code editor. Edit the provided code
|
|
64
|
-
|
|
65
|
-
|
|
68
|
+
content: `You are a precise code editor. Edit the provided code EXACTLY as the user instructs.
|
|
69
|
+
|
|
70
|
+
MANDATORY RULES:
|
|
71
|
+
1. Return ONLY the complete modified file content. No explanation, no markdown.
|
|
72
|
+
2. Preserve all original formatting, indentation, and style.
|
|
73
|
+
3. Make ONLY the changes the instruction asks for — nothing more, nothing less.
|
|
74
|
+
4. If the instruction says "Replace X with Y", then X must become Y verbatim.
|
|
75
|
+
5. Do NOT add, remove, or rewrite lines the instruction didn't mention.
|
|
76
|
+
6. Do NOT summarize, shorten, paraphrase, or "improve" the requested text.
|
|
77
|
+
7. The instruction text is LITERAL — reproduce it character-for-character.`,
|
|
66
78
|
},
|
|
67
79
|
{
|
|
68
80
|
role: 'user',
|
|
@@ -76,7 +88,7 @@ ${file.content}
|
|
|
76
88
|
|
|
77
89
|
Instruction: ${instruction}
|
|
78
90
|
|
|
79
|
-
Return the complete modified
|
|
91
|
+
Return the complete modified file content:`,
|
|
80
92
|
},
|
|
81
93
|
], options.model);
|
|
82
94
|
spinner.stop();
|
|
@@ -148,12 +160,17 @@ Return the complete modified code:`,
|
|
|
148
160
|
}
|
|
149
161
|
}
|
|
150
162
|
extractCode(response, language) {
|
|
151
|
-
// Try to extract code block
|
|
163
|
+
// Try to extract code block (language-specific first, then any)
|
|
152
164
|
const codeBlockRegex = new RegExp(`\`\`\`(?:${language})?\\n([\\s\\S]*?)\`\`\``, 'i');
|
|
153
165
|
const match = response.match(codeBlockRegex);
|
|
154
166
|
if (match) {
|
|
155
167
|
return match[1].trim();
|
|
156
168
|
}
|
|
169
|
+
// Try generic code block
|
|
170
|
+
const genericMatch = response.match(/```\w*\n([\s\S]*?)```/);
|
|
171
|
+
if (genericMatch) {
|
|
172
|
+
return genericMatch[1].trim();
|
|
173
|
+
}
|
|
157
174
|
// If no code block, check if response looks like code
|
|
158
175
|
const trimmed = response.trim();
|
|
159
176
|
if (!trimmed.startsWith('```') && !trimmed.includes('Here') && !trimmed.includes('I ')) {
|
|
@@ -18,6 +18,11 @@ export declare class GenerateCommand {
|
|
|
18
18
|
private fileUtils;
|
|
19
19
|
constructor(config: Config, logger: Logger);
|
|
20
20
|
run(description: string, options: GenerateOptions): Promise<void>;
|
|
21
|
+
/**
|
|
22
|
+
* Strip markdown code fences the model may wrap around the output.
|
|
23
|
+
* The CLI asks for raw code but some models still wrap in ```lang ... ```.
|
|
24
|
+
*/
|
|
25
|
+
private stripMarkdownFences;
|
|
21
26
|
private highlightCode;
|
|
22
27
|
private highlightLine;
|
|
23
28
|
private saveToFile;
|
|
@@ -81,13 +81,17 @@ class GenerateCommand {
|
|
|
81
81
|
code = await this.api.generateCode(description, options.language, options.model);
|
|
82
82
|
spinner.stop();
|
|
83
83
|
}
|
|
84
|
-
//
|
|
85
|
-
this.
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
84
|
+
// Strip any markdown fences the model may have wrapped around the code
|
|
85
|
+
code = this.stripMarkdownFences(code, options.language);
|
|
86
|
+
// Display generated code (skip display when --output is set to avoid noise)
|
|
87
|
+
if (!options.output) {
|
|
88
|
+
this.logger.section('Generated Code');
|
|
89
|
+
console.log(chalk_1.default.gray('─'.repeat(60)));
|
|
90
|
+
console.log(this.highlightCode(code, options.language));
|
|
91
|
+
console.log(chalk_1.default.gray('─'.repeat(60)));
|
|
92
|
+
console.log();
|
|
93
|
+
}
|
|
94
|
+
// Save options — when --output is specified, save directly (non-interactive)
|
|
91
95
|
if (options.output) {
|
|
92
96
|
await this.saveToFile(options.output, code);
|
|
93
97
|
}
|
|
@@ -100,6 +104,25 @@ class GenerateCommand {
|
|
|
100
104
|
this.logger.error('Generation failed:', error.message);
|
|
101
105
|
}
|
|
102
106
|
}
|
|
107
|
+
/**
|
|
108
|
+
* Strip markdown code fences the model may wrap around the output.
|
|
109
|
+
* The CLI asks for raw code but some models still wrap in ```lang ... ```.
|
|
110
|
+
*/
|
|
111
|
+
stripMarkdownFences(code, language) {
|
|
112
|
+
const trimmed = code.trim();
|
|
113
|
+
// Try language-specific fence first
|
|
114
|
+
const langFenceRe = new RegExp(`^\`\`\`(?:${language})?\\s*\\n([\\s\\S]*?)\\n?\`\`\`\\s*$`, 'i');
|
|
115
|
+
const langMatch = trimmed.match(langFenceRe);
|
|
116
|
+
if (langMatch) {
|
|
117
|
+
return langMatch[1].trim();
|
|
118
|
+
}
|
|
119
|
+
// Try generic fence
|
|
120
|
+
const genericMatch = trimmed.match(/^```\w*\s*\n([\s\S]*?)\n?```\s*$/);
|
|
121
|
+
if (genericMatch) {
|
|
122
|
+
return genericMatch[1].trim();
|
|
123
|
+
}
|
|
124
|
+
return code;
|
|
125
|
+
}
|
|
103
126
|
highlightCode(code, language) {
|
|
104
127
|
// Basic syntax highlighting
|
|
105
128
|
// In production, use a proper library like highlight.js
|
package/dist/commands/repo.js
CHANGED
|
@@ -399,7 +399,8 @@ class RepoCommand {
|
|
|
399
399
|
console.log(chalk_1.default.gray('\nTip: Use `vigthoria repo pull <name>` to restore this project anywhere.\n'));
|
|
400
400
|
}
|
|
401
401
|
catch (error) {
|
|
402
|
-
spinner.
|
|
402
|
+
spinner.stop();
|
|
403
|
+
this.logger.error('Push failed');
|
|
403
404
|
const errMsg = this.formatRepoError(error);
|
|
404
405
|
console.log(chalk_1.default.red(`\n❌ Error: ${errMsg}\n`));
|
|
405
406
|
}
|
|
@@ -486,7 +487,8 @@ class RepoCommand {
|
|
|
486
487
|
console.log();
|
|
487
488
|
}
|
|
488
489
|
catch (error) {
|
|
489
|
-
spinner.
|
|
490
|
+
spinner.stop();
|
|
491
|
+
this.logger.error('Pull failed');
|
|
490
492
|
const errMsg = this.formatRepoError(error);
|
|
491
493
|
console.log(chalk_1.default.red(`\n❌ Error: ${errMsg}\n`));
|
|
492
494
|
}
|
|
@@ -584,7 +586,8 @@ class RepoCommand {
|
|
|
584
586
|
console.log(chalk_1.default.gray(' vigthoria repo share <name> - Share a project\n'));
|
|
585
587
|
}
|
|
586
588
|
catch (error) {
|
|
587
|
-
spinner.
|
|
589
|
+
spinner.stop();
|
|
590
|
+
this.logger.error('List failed');
|
|
588
591
|
const errMsg = this.formatRepoError(error);
|
|
589
592
|
console.log(chalk_1.default.red(`\n❌ Error: ${errMsg}\n`));
|
|
590
593
|
}
|
|
@@ -634,7 +637,8 @@ class RepoCommand {
|
|
|
634
637
|
}
|
|
635
638
|
}
|
|
636
639
|
catch (error) {
|
|
637
|
-
spinner.
|
|
640
|
+
spinner.stop();
|
|
641
|
+
this.logger.error('Status check failed');
|
|
638
642
|
const errMsg = error instanceof Error ? error.message : 'Unknown error';
|
|
639
643
|
console.log(chalk_1.default.red(`\n❌ Error: ${errMsg}\n`));
|
|
640
644
|
}
|
|
@@ -666,7 +670,8 @@ class RepoCommand {
|
|
|
666
670
|
console.log(chalk_1.default.gray('\n Anyone with this link can view/download the project.\n'));
|
|
667
671
|
}
|
|
668
672
|
catch (error) {
|
|
669
|
-
spinner.
|
|
673
|
+
spinner.stop();
|
|
674
|
+
this.logger.error('Share failed');
|
|
670
675
|
const errMsg = error instanceof Error ? error.message : 'Unknown error';
|
|
671
676
|
console.log(chalk_1.default.red(`\n❌ Error: ${errMsg}\n`));
|
|
672
677
|
}
|
|
@@ -700,7 +705,8 @@ class RepoCommand {
|
|
|
700
705
|
console.log(chalk_1.default.gray('\nNote: Your local files are not affected.\n'));
|
|
701
706
|
}
|
|
702
707
|
catch (error) {
|
|
703
|
-
spinner.
|
|
708
|
+
spinner.stop();
|
|
709
|
+
this.logger.error('Delete failed');
|
|
704
710
|
const errMsg = error instanceof Error ? error.message : 'Unknown error';
|
|
705
711
|
console.log(chalk_1.default.red(`\n❌ Error: ${errMsg}\n`));
|
|
706
712
|
}
|
|
@@ -728,7 +734,8 @@ class RepoCommand {
|
|
|
728
734
|
await this.pull(data.project.project_name, options);
|
|
729
735
|
}
|
|
730
736
|
catch (error) {
|
|
731
|
-
spinner.
|
|
737
|
+
spinner.stop();
|
|
738
|
+
this.logger.error('Clone failed');
|
|
732
739
|
const errMsg = error instanceof Error ? error.message : 'Unknown error';
|
|
733
740
|
console.log(chalk_1.default.red(`\n❌ Error: ${errMsg}\n`));
|
|
734
741
|
}
|
package/dist/index.js
CHANGED
|
@@ -98,7 +98,7 @@ function getVersion() {
|
|
|
98
98
|
catch (e) {
|
|
99
99
|
// Fallback to hardcoded version
|
|
100
100
|
}
|
|
101
|
-
return '1.6.
|
|
101
|
+
return '1.6.22';
|
|
102
102
|
}
|
|
103
103
|
const VERSION = getVersion();
|
|
104
104
|
/**
|
|
@@ -204,6 +204,7 @@ async function main() {
|
|
|
204
204
|
.option('-w, --workflow <selector>', 'Route prompts through a named or explicit VigFlow workflow target')
|
|
205
205
|
.option('--json', 'Emit machine-readable JSON output for direct prompt runs', false)
|
|
206
206
|
.option('--auto-approve', 'Auto-approve agent actions (dangerous!)', false)
|
|
207
|
+
.option('--bridge <url>', 'Connect to Vigthoria Commando Bridge for remote admin observability')
|
|
207
208
|
.action(async (options) => {
|
|
208
209
|
const chat = new chat_js_1.ChatCommand(config, logger);
|
|
209
210
|
await chat.run({
|
|
@@ -217,6 +218,7 @@ async function main() {
|
|
|
217
218
|
autoApprove: options.autoApprove,
|
|
218
219
|
resume: options.resume,
|
|
219
220
|
prompt: options.prompt,
|
|
221
|
+
bridge: options.bridge,
|
|
220
222
|
});
|
|
221
223
|
});
|
|
222
224
|
program
|
|
@@ -231,6 +233,7 @@ async function main() {
|
|
|
231
233
|
.option('-w, --workflow <selector>', 'Route prompts through a named or explicit VigFlow workflow target')
|
|
232
234
|
.option('--json', 'Emit machine-readable JSON output for direct prompt runs', false)
|
|
233
235
|
.option('--auto-approve', 'Auto-approve agent actions (dangerous!)', false)
|
|
236
|
+
.option('--bridge <url>', 'Connect to Vigthoria Commando Bridge for remote admin observability')
|
|
234
237
|
.action(async (options) => {
|
|
235
238
|
const chat = new chat_js_1.ChatCommand(config, logger);
|
|
236
239
|
await chat.run({
|
|
@@ -244,6 +247,7 @@ async function main() {
|
|
|
244
247
|
autoApprove: options.autoApprove,
|
|
245
248
|
resume: true,
|
|
246
249
|
prompt: options.prompt,
|
|
250
|
+
bridge: options.bridge,
|
|
247
251
|
});
|
|
248
252
|
});
|
|
249
253
|
// Agent command - Agentic mode (Vigthoria Autonomous)
|
|
@@ -259,6 +263,7 @@ async function main() {
|
|
|
259
263
|
.option('-w, --workflow <selector>', 'Run the prompt through a named or explicit VigFlow workflow target')
|
|
260
264
|
.option('--json', 'Emit machine-readable JSON output for direct prompt runs', false)
|
|
261
265
|
.option('--auto-approve', 'Auto-approve all actions (dangerous!)', false)
|
|
266
|
+
.option('--bridge <url>', 'Connect to Vigthoria Commando Bridge for remote admin observability')
|
|
262
267
|
.action(async (options) => {
|
|
263
268
|
const chat = new chat_js_1.ChatCommand(config, logger);
|
|
264
269
|
await chat.run({
|
|
@@ -272,6 +277,7 @@ async function main() {
|
|
|
272
277
|
json: options.json,
|
|
273
278
|
autoApprove: options.autoApprove,
|
|
274
279
|
prompt: options.prompt,
|
|
280
|
+
bridge: options.bridge,
|
|
275
281
|
});
|
|
276
282
|
});
|
|
277
283
|
program
|
|
@@ -285,6 +291,7 @@ async function main() {
|
|
|
285
291
|
.option('-w, --workflow <selector>', 'Run the prompt through a named or explicit VigFlow workflow target')
|
|
286
292
|
.option('--save-plan', 'Save the completed BMAD plan into VigFlow for rerun and audit', false)
|
|
287
293
|
.option('--json', 'Emit machine-readable JSON output for direct prompt runs', false)
|
|
294
|
+
.option('--bridge <url>', 'Connect to Vigthoria Commando Bridge for remote admin observability')
|
|
288
295
|
.action(async (options) => {
|
|
289
296
|
const chat = new chat_js_1.ChatCommand(config, logger);
|
|
290
297
|
await chat.run({
|
|
@@ -298,6 +305,7 @@ async function main() {
|
|
|
298
305
|
savePlan: options.savePlan,
|
|
299
306
|
json: options.json,
|
|
300
307
|
prompt: options.prompt,
|
|
308
|
+
bridge: options.bridge,
|
|
301
309
|
});
|
|
302
310
|
});
|
|
303
311
|
program
|