vigthoria-cli 1.6.18 → 1.6.19
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.js +29 -2
- package/dist/commands/edit.d.ts +1 -0
- package/dist/commands/edit.js +7 -2
- package/dist/commands/workflow.js +31 -5
- package/dist/index.js +1 -0
- package/dist/utils/api.d.ts +12 -0
- package/dist/utils/api.js +103 -5
- package/package.json +1 -1
package/dist/commands/chat.js
CHANGED
|
@@ -118,7 +118,13 @@ class ChatCommand {
|
|
|
118
118
|
return this.getDefaultChatModel();
|
|
119
119
|
}
|
|
120
120
|
isLegacyAgentFallbackAllowed() {
|
|
121
|
-
|
|
121
|
+
// CLI always has local file access, so fallback to local agent loop
|
|
122
|
+
// is safe and should be the default when V3 agent is unreachable or
|
|
123
|
+
// rejects the request (e.g. context too large).
|
|
124
|
+
if (process.env.VIGTHORIA_ALLOW_LEGACY_AGENT_FALLBACK === '0') {
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
127
|
+
return true;
|
|
122
128
|
}
|
|
123
129
|
resolveAgentExecutionPolicy(prompt) {
|
|
124
130
|
const explicitModel = this.modelExplicitlySelected;
|
|
@@ -657,11 +663,32 @@ class ChatCommand {
|
|
|
657
663
|
if (spinner) {
|
|
658
664
|
spinner.fail('Operator workflow failed');
|
|
659
665
|
}
|
|
660
|
-
|
|
666
|
+
const errorMsg = error.message || 'Operator workflow failed with an unknown error.';
|
|
667
|
+
if (this.jsonOutput) {
|
|
668
|
+
process.exitCode = 1;
|
|
669
|
+
console.log(JSON.stringify({
|
|
670
|
+
success: false,
|
|
671
|
+
mode: 'operator',
|
|
672
|
+
content: '',
|
|
673
|
+
error: errorMsg,
|
|
674
|
+
}, null, 2));
|
|
675
|
+
}
|
|
676
|
+
else {
|
|
677
|
+
this.logger.error(errorMsg);
|
|
678
|
+
}
|
|
661
679
|
}
|
|
662
680
|
}
|
|
663
681
|
async runSimplePrompt(prompt) {
|
|
664
682
|
this.lastActionableUserInput = prompt;
|
|
683
|
+
// In non-agent chat mode the model has no tool access. Inject a
|
|
684
|
+
// grounding constraint so it doesn't fabricate file contents.
|
|
685
|
+
const needsGrounding = /(repo|file|code|project|workspace|source|inspect|analyze|audit|review)/i.test(prompt);
|
|
686
|
+
if (needsGrounding && !this.messages.some(m => m.role === 'system' && m.content.includes('no direct file access'))) {
|
|
687
|
+
this.messages.push({
|
|
688
|
+
role: 'system',
|
|
689
|
+
content: 'You are in simple chat mode with no direct file access. Do not fabricate file contents, search results, or analysis steps. If the user asks about specific files, advise them to use agent mode (vig chat --agent) for grounded repo analysis.',
|
|
690
|
+
});
|
|
691
|
+
}
|
|
665
692
|
this.messages.push({ role: 'user', content: this.buildExecutionPrompt(prompt) });
|
|
666
693
|
const spinner = this.jsonOutput ? null : (0, logger_js_1.createSpinner)({ text: 'Thinking...', spinner: 'clock' }).start();
|
|
667
694
|
try {
|
package/dist/commands/edit.d.ts
CHANGED
package/dist/commands/edit.js
CHANGED
|
@@ -86,8 +86,13 @@ Return the complete modified code:`,
|
|
|
86
86
|
this.logger.error('Failed to generate valid code changes');
|
|
87
87
|
return;
|
|
88
88
|
}
|
|
89
|
-
// Show diff
|
|
90
|
-
|
|
89
|
+
// Show diff and apply
|
|
90
|
+
if (options.apply) {
|
|
91
|
+
await this.applyFix(file.path, file.content, modifiedCode);
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
await this.showDiffAndConfirm(file.path, file.content, modifiedCode);
|
|
95
|
+
}
|
|
91
96
|
}
|
|
92
97
|
catch (error) {
|
|
93
98
|
spinner.stop();
|
|
@@ -48,10 +48,23 @@ class WorkflowCommand {
|
|
|
48
48
|
}
|
|
49
49
|
async templates(options) {
|
|
50
50
|
this.ensureAuthenticated(Boolean(options.json));
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
51
|
+
let templates;
|
|
52
|
+
try {
|
|
53
|
+
templates = await this.api.listVigFlowTemplates({
|
|
54
|
+
category: options.category,
|
|
55
|
+
search: options.search,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
catch (error) {
|
|
59
|
+
const msg = `Workflow service is not reachable: ${error.message}`;
|
|
60
|
+
if (options.json) {
|
|
61
|
+
this.printJson({ success: false, error: msg, templates: [] });
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
this.logger.error(msg);
|
|
65
|
+
}
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
55
68
|
if (options.json) {
|
|
56
69
|
this.printJson({ success: true, templates });
|
|
57
70
|
return;
|
|
@@ -70,7 +83,20 @@ class WorkflowCommand {
|
|
|
70
83
|
}
|
|
71
84
|
async list(options) {
|
|
72
85
|
this.ensureAuthenticated(Boolean(options.json));
|
|
73
|
-
|
|
86
|
+
let workflows;
|
|
87
|
+
try {
|
|
88
|
+
workflows = await this.api.listVigFlowWorkflows();
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
const msg = `Workflow service is not reachable: ${error.message}`;
|
|
92
|
+
if (options.json) {
|
|
93
|
+
this.printJson({ success: false, error: msg, workflows: [] });
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
this.logger.error(msg);
|
|
97
|
+
}
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
74
100
|
if (options.json) {
|
|
75
101
|
this.printJson({ success: true, workflows });
|
|
76
102
|
return;
|
package/dist/index.js
CHANGED
|
@@ -316,6 +316,7 @@ async function main() {
|
|
|
316
316
|
.description('Edit a file with AI assistance')
|
|
317
317
|
.option('-i, --instruction <text>', 'Editing instruction')
|
|
318
318
|
.option('-m, --model <model>', 'Select AI model', 'code')
|
|
319
|
+
.option('--apply', 'Automatically apply changes without confirmation', false)
|
|
319
320
|
.action(async (file, options) => {
|
|
320
321
|
const edit = new edit_js_1.EditCommand(config, logger);
|
|
321
322
|
await edit.run(file, options);
|
package/dist/utils/api.d.ts
CHANGED
|
@@ -227,7 +227,19 @@ export declare class APIClient {
|
|
|
227
227
|
executionOptions?: Record<string, unknown>;
|
|
228
228
|
}): Promise<VigFlowExecutionResult>;
|
|
229
229
|
getVigFlowExecutionStatus(executionId: string): Promise<VigFlowExecutionStatus>;
|
|
230
|
+
/** Maximum serialized context length accepted by the V3 server. */
|
|
231
|
+
private static readonly V3_CONTEXT_CHAR_LIMIT;
|
|
230
232
|
buildV3AgentContext(context?: Record<string, any>): string;
|
|
233
|
+
/**
|
|
234
|
+
* Compact a V3 context payload so the serialized JSON stays under
|
|
235
|
+
* the server's character limit. Progressively sheds bulk:
|
|
236
|
+
* 1. Trim workspaceFiles values to fit budget
|
|
237
|
+
* 2. Drop workspaceFiles entirely
|
|
238
|
+
* 3. Truncate history
|
|
239
|
+
* 4. Truncate file list
|
|
240
|
+
* 5. Drop readmeExcerpt
|
|
241
|
+
*/
|
|
242
|
+
private compactV3Context;
|
|
231
243
|
buildMinimalV3AgentContext(context?: Record<string, any>): string;
|
|
232
244
|
private extractEmergencyAppName;
|
|
233
245
|
private materializeEmergencySaaSWorkspace;
|
package/dist/utils/api.js
CHANGED
|
@@ -306,12 +306,14 @@ class APIClient {
|
|
|
306
306
|
return [...new Set(urls)];
|
|
307
307
|
}
|
|
308
308
|
getVigFlowBaseUrls() {
|
|
309
|
+
const configuredApiUrl = String(this.config.get('apiUrl') || 'https://coder.vigthoria.io').replace(/\/$/, '');
|
|
309
310
|
const urls = [
|
|
310
311
|
process.env.VIGTHORIA_VIGFLOW_URL,
|
|
311
312
|
process.env.VIGFLOW_URL,
|
|
312
313
|
process.env.WORKFLOW_BUILDER_URL,
|
|
313
314
|
'http://127.0.0.1:5060',
|
|
314
315
|
'http://127.0.0.1:5050',
|
|
316
|
+
`${configuredApiUrl}/api/vigflow`,
|
|
315
317
|
].filter(Boolean).map((url) => String(url).replace(/\/$/, ''));
|
|
316
318
|
return [...new Set(urls)];
|
|
317
319
|
}
|
|
@@ -888,6 +890,8 @@ class APIClient {
|
|
|
888
890
|
return payload.execution;
|
|
889
891
|
});
|
|
890
892
|
}
|
|
893
|
+
/** Maximum serialized context length accepted by the V3 server. */
|
|
894
|
+
static V3_CONTEXT_CHAR_LIMIT = 95_000;
|
|
891
895
|
buildV3AgentContext(context = {}) {
|
|
892
896
|
const resolvedContext = this.ensureExecutionContext(context);
|
|
893
897
|
const targetPath = resolvedContext.targetPath || resolvedContext.projectPath || resolvedContext.workspacePath || resolvedContext.projectRoot || process.cwd();
|
|
@@ -896,7 +900,7 @@ class APIClient {
|
|
|
896
900
|
const localWorkspaceSummary = this.buildLocalWorkspaceSummary(localWorkspacePath);
|
|
897
901
|
const requestedModel = String(resolvedContext.model || resolvedContext.requestedModel || 'agent');
|
|
898
902
|
const resolvedModel = this.resolvePermittedModelId(requestedModel);
|
|
899
|
-
|
|
903
|
+
const payload = {
|
|
900
904
|
workspace: resolvedContext.workspace || null,
|
|
901
905
|
activeFile: resolvedContext.activeFile || null,
|
|
902
906
|
history: resolvedContext.history || [],
|
|
@@ -922,7 +926,89 @@ class APIClient {
|
|
|
922
926
|
requestStartedAt: resolvedContext.requestStartedAt,
|
|
923
927
|
subscriptionPlan: this.config.getNormalizedPlan() || null,
|
|
924
928
|
email: this.config.get('email') || null,
|
|
925
|
-
}
|
|
929
|
+
};
|
|
930
|
+
return this.compactV3Context(payload);
|
|
931
|
+
}
|
|
932
|
+
/**
|
|
933
|
+
* Compact a V3 context payload so the serialized JSON stays under
|
|
934
|
+
* the server's character limit. Progressively sheds bulk:
|
|
935
|
+
* 1. Trim workspaceFiles values to fit budget
|
|
936
|
+
* 2. Drop workspaceFiles entirely
|
|
937
|
+
* 3. Truncate history
|
|
938
|
+
* 4. Truncate file list
|
|
939
|
+
* 5. Drop readmeExcerpt
|
|
940
|
+
*/
|
|
941
|
+
compactV3Context(payload) {
|
|
942
|
+
const LIMIT = APIClient.V3_CONTEXT_CHAR_LIMIT;
|
|
943
|
+
let json = JSON.stringify(payload);
|
|
944
|
+
if (json.length <= LIMIT)
|
|
945
|
+
return json;
|
|
946
|
+
// Phase 1 — shrink workspaceFiles to fit
|
|
947
|
+
const summary = payload.localWorkspaceSummary;
|
|
948
|
+
if (summary?.workspaceFiles && typeof summary.workspaceFiles === 'object') {
|
|
949
|
+
const fileEntries = Object.entries(summary.workspaceFiles);
|
|
950
|
+
const overhead = json.length - JSON.stringify(summary.workspaceFiles).length;
|
|
951
|
+
const budget = LIMIT - overhead - 512; // reserve a little headroom
|
|
952
|
+
if (budget > 0) {
|
|
953
|
+
const trimmed = {};
|
|
954
|
+
let used = 2; // {}
|
|
955
|
+
for (const [k, v] of fileEntries) {
|
|
956
|
+
const entryLen = JSON.stringify(k).length + 1 + JSON.stringify(v).length + 1;
|
|
957
|
+
if (used + entryLen > budget)
|
|
958
|
+
break;
|
|
959
|
+
trimmed[k] = v;
|
|
960
|
+
used += entryLen;
|
|
961
|
+
}
|
|
962
|
+
summary.workspaceFiles = trimmed;
|
|
963
|
+
}
|
|
964
|
+
else {
|
|
965
|
+
delete summary.workspaceFiles;
|
|
966
|
+
}
|
|
967
|
+
json = JSON.stringify(payload);
|
|
968
|
+
if (json.length <= LIMIT)
|
|
969
|
+
return json;
|
|
970
|
+
}
|
|
971
|
+
// Phase 2 — drop workspaceFiles entirely
|
|
972
|
+
if (summary?.workspaceFiles) {
|
|
973
|
+
delete summary.workspaceFiles;
|
|
974
|
+
json = JSON.stringify(payload);
|
|
975
|
+
if (json.length <= LIMIT)
|
|
976
|
+
return json;
|
|
977
|
+
}
|
|
978
|
+
// Phase 3 — truncate history to last 6 messages
|
|
979
|
+
if (Array.isArray(payload.history) && payload.history.length > 6) {
|
|
980
|
+
payload.history = payload.history.slice(-6);
|
|
981
|
+
json = JSON.stringify(payload);
|
|
982
|
+
if (json.length <= LIMIT)
|
|
983
|
+
return json;
|
|
984
|
+
}
|
|
985
|
+
// Phase 4 — truncate file list
|
|
986
|
+
if (summary?.files && Array.isArray(summary.files) && summary.files.length > 15) {
|
|
987
|
+
summary.files = summary.files.slice(0, 15);
|
|
988
|
+
json = JSON.stringify(payload);
|
|
989
|
+
if (json.length <= LIMIT)
|
|
990
|
+
return json;
|
|
991
|
+
}
|
|
992
|
+
// Phase 5 — drop readmeExcerpt
|
|
993
|
+
if (summary?.readmeExcerpt) {
|
|
994
|
+
delete summary.readmeExcerpt;
|
|
995
|
+
json = JSON.stringify(payload);
|
|
996
|
+
if (json.length <= LIMIT)
|
|
997
|
+
return json;
|
|
998
|
+
}
|
|
999
|
+
// Phase 6 — drop history entirely
|
|
1000
|
+
if (Array.isArray(payload.history) && payload.history.length > 0) {
|
|
1001
|
+
payload.history = [];
|
|
1002
|
+
json = JSON.stringify(payload);
|
|
1003
|
+
if (json.length <= LIMIT)
|
|
1004
|
+
return json;
|
|
1005
|
+
}
|
|
1006
|
+
// Phase 7 — drop localWorkspaceSummary entirely as last resort
|
|
1007
|
+
if (payload.localWorkspaceSummary) {
|
|
1008
|
+
payload.localWorkspaceSummary = { path: summary?.path, name: summary?.name, fileCount: summary?.fileCount };
|
|
1009
|
+
json = JSON.stringify(payload);
|
|
1010
|
+
}
|
|
1011
|
+
return json;
|
|
926
1012
|
}
|
|
927
1013
|
buildMinimalV3AgentContext(context = {}) {
|
|
928
1014
|
const resolvedContext = this.ensureExecutionContext(context);
|
|
@@ -3024,8 +3110,11 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
3024
3110
|
}
|
|
3025
3111
|
// Code operations - Using Vigthoria Centralized API
|
|
3026
3112
|
async generateCode(prompt, language, model) {
|
|
3113
|
+
// Prepend scope-enforcement instruction so the model doesn't expand
|
|
3114
|
+
// a small task into an oversized glossy production page.
|
|
3115
|
+
const scopedPrompt = `IMPORTANT: Follow the user's scope literally. If they ask for something small or minimal, produce exactly that — no extra styling, no external dependencies, no landing-page treatment.\n\n${prompt}`;
|
|
3027
3116
|
const response = await this.client.post('/api/ai/generate', {
|
|
3028
|
-
prompt,
|
|
3117
|
+
prompt: scopedPrompt,
|
|
3029
3118
|
language,
|
|
3030
3119
|
model: this.resolvePermittedModelId(model),
|
|
3031
3120
|
});
|
|
@@ -3058,7 +3147,12 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
3058
3147
|
code,
|
|
3059
3148
|
language,
|
|
3060
3149
|
});
|
|
3061
|
-
|
|
3150
|
+
const raw = response.data ?? {};
|
|
3151
|
+
return {
|
|
3152
|
+
score: typeof raw.score === 'number' ? raw.score : 0,
|
|
3153
|
+
issues: Array.isArray(raw.issues) ? raw.issues : [],
|
|
3154
|
+
suggestions: Array.isArray(raw.suggestions) ? raw.suggestions : [],
|
|
3155
|
+
};
|
|
3062
3156
|
}
|
|
3063
3157
|
async fixCode(code, language, fixType) {
|
|
3064
3158
|
const response = await this.client.post('/api/ai/fix', {
|
|
@@ -3066,7 +3160,11 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
3066
3160
|
language,
|
|
3067
3161
|
fixType,
|
|
3068
3162
|
});
|
|
3069
|
-
|
|
3163
|
+
const raw = response.data ?? {};
|
|
3164
|
+
return {
|
|
3165
|
+
fixed: typeof raw.fixed === 'string' ? raw.fixed : (typeof raw.code === 'string' ? raw.code : code),
|
|
3166
|
+
changes: Array.isArray(raw.changes) ? raw.changes : [],
|
|
3167
|
+
};
|
|
3070
3168
|
}
|
|
3071
3169
|
// Model resolution - maps Vigthoria model names to internal IDs
|
|
3072
3170
|
// INTERNAL USE ONLY - users see only Vigthoria branding
|