vigthoria-cli 1.10.50 → 1.10.55
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/background.d.ts +19 -0
- package/dist/commands/background.js +160 -0
- package/dist/commands/chat.js +89 -6
- package/dist/index.js +55 -2
- package/dist/utils/api.d.ts +30 -0
- package/dist/utils/api.js +624 -160
- package/package.json +1 -1
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Config } from '../utils/config.js';
|
|
2
|
+
import { Logger } from '../utils/logger.js';
|
|
3
|
+
interface BackgroundOptions {
|
|
4
|
+
json?: boolean;
|
|
5
|
+
limit?: number;
|
|
6
|
+
workspace?: string;
|
|
7
|
+
}
|
|
8
|
+
export declare class BackgroundCommand {
|
|
9
|
+
private config;
|
|
10
|
+
private logger;
|
|
11
|
+
private api;
|
|
12
|
+
constructor(config: Config, logger: Logger);
|
|
13
|
+
start(promptParts: string[], options?: BackgroundOptions): Promise<void>;
|
|
14
|
+
list(options?: BackgroundOptions): Promise<void>;
|
|
15
|
+
status(jobId: string, options?: BackgroundOptions): Promise<void>;
|
|
16
|
+
apply(jobId: string, options?: BackgroundOptions): Promise<void>;
|
|
17
|
+
cancel(jobId: string, options?: BackgroundOptions): Promise<void>;
|
|
18
|
+
}
|
|
19
|
+
export {};
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { createSpinner, CH } from '../utils/logger.js';
|
|
3
|
+
import { APIClient } from '../utils/api.js';
|
|
4
|
+
export class BackgroundCommand {
|
|
5
|
+
config;
|
|
6
|
+
logger;
|
|
7
|
+
api;
|
|
8
|
+
constructor(config, logger) {
|
|
9
|
+
this.config = config;
|
|
10
|
+
this.logger = logger;
|
|
11
|
+
this.api = new APIClient(config, logger);
|
|
12
|
+
}
|
|
13
|
+
async start(promptParts, options = {}) {
|
|
14
|
+
const prompt = promptParts.join(' ').trim();
|
|
15
|
+
if (!prompt) {
|
|
16
|
+
this.logger.error('Usage: vigthoria background start "<task>"');
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
const workspacePath = options.workspace || process.cwd();
|
|
20
|
+
const spinner = createSpinner('Starting background agent job...').start();
|
|
21
|
+
try {
|
|
22
|
+
const job = await this.api.startV3BackgroundJob(prompt, {
|
|
23
|
+
workspacePath,
|
|
24
|
+
projectPath: workspacePath,
|
|
25
|
+
targetPath: workspacePath,
|
|
26
|
+
localMachineCapable: true,
|
|
27
|
+
executionSurface: 'cli',
|
|
28
|
+
clientSurface: 'cli',
|
|
29
|
+
clientToolExecution: false,
|
|
30
|
+
});
|
|
31
|
+
spinner.stop();
|
|
32
|
+
if (options.json) {
|
|
33
|
+
console.log(JSON.stringify(job, null, 2));
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
console.log(chalk.green(`${CH.success} Background job started`));
|
|
37
|
+
console.log(chalk.gray(` Job: ${job.job_id}`));
|
|
38
|
+
console.log(chalk.gray(` Status: ${job.status}`));
|
|
39
|
+
console.log(chalk.gray(` Workspace: ${workspacePath}`));
|
|
40
|
+
console.log();
|
|
41
|
+
console.log(chalk.gray(`Use ${chalk.cyan(`vigthoria background status ${job.job_id}`)} to check progress.`));
|
|
42
|
+
console.log(chalk.gray(`Use ${chalk.cyan(`vigthoria background apply ${job.job_id}`)} when it is completed.`));
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
spinner.stop();
|
|
46
|
+
this.logger.error(error?.message || String(error));
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
async list(options = {}) {
|
|
50
|
+
const spinner = createSpinner('Loading background jobs...').start();
|
|
51
|
+
try {
|
|
52
|
+
const jobs = await this.api.listV3BackgroundJobs(options.limit || 20);
|
|
53
|
+
spinner.stop();
|
|
54
|
+
if (options.json) {
|
|
55
|
+
console.log(JSON.stringify({ jobs }, null, 2));
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
if (jobs.length === 0) {
|
|
59
|
+
console.log(chalk.gray('No background jobs found.'));
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
console.log(chalk.bold(`\n${CH.success} Background Jobs\n`));
|
|
63
|
+
for (const job of jobs) {
|
|
64
|
+
const color = job.status === 'completed' ? chalk.green : job.status === 'failed' ? chalk.red : job.status === 'cancelled' ? chalk.yellow : chalk.cyan;
|
|
65
|
+
console.log(`${color(String(job.status || 'unknown').padEnd(10))} ${chalk.cyan(job.job_id)} ${chalk.gray(job.updated_at || '')}`);
|
|
66
|
+
console.log(chalk.gray(` ${String(job.request || '').slice(0, 100)}`));
|
|
67
|
+
console.log(chalk.gray(` files: ${job.file_count || 0} workspace: ${job.local_workspace_path || job.workspace_name || '-'}`));
|
|
68
|
+
}
|
|
69
|
+
console.log();
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
spinner.stop();
|
|
73
|
+
this.logger.error(error?.message || String(error));
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
async status(jobId, options = {}) {
|
|
77
|
+
if (!jobId) {
|
|
78
|
+
this.logger.error('Usage: vigthoria background status <job-id>');
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
const spinner = createSpinner('Loading background job...').start();
|
|
82
|
+
try {
|
|
83
|
+
const job = await this.api.getV3BackgroundJob(jobId);
|
|
84
|
+
spinner.stop();
|
|
85
|
+
if (options.json) {
|
|
86
|
+
console.log(JSON.stringify(job, null, 2));
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
console.log(chalk.bold(`\nBackground Job ${chalk.cyan(job.job_id)}\n`));
|
|
90
|
+
console.log(`Status: ${job.status}`);
|
|
91
|
+
console.log(`Files: ${job.file_count || 0}`);
|
|
92
|
+
console.log(`Updated: ${job.updated_at || '-'}`);
|
|
93
|
+
console.log(`Workspace: ${job.local_workspace_path || job.workspace_name || '-'}`);
|
|
94
|
+
if (job.error)
|
|
95
|
+
console.log(chalk.red(`Error: ${job.error}`));
|
|
96
|
+
console.log(chalk.gray(`\n${String(job.request || '').slice(0, 500)}`));
|
|
97
|
+
if (job.status === 'completed' && (job.file_count || 0) > 0) {
|
|
98
|
+
console.log(chalk.gray(`\nUse ${chalk.cyan(`vigthoria background apply ${job.job_id}`)} to apply files locally.`));
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
catch (error) {
|
|
102
|
+
spinner.stop();
|
|
103
|
+
this.logger.error(error?.message || String(error));
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
async apply(jobId, options = {}) {
|
|
107
|
+
if (!jobId) {
|
|
108
|
+
this.logger.error('Usage: vigthoria background apply <job-id>');
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
const workspacePath = options.workspace || process.cwd();
|
|
112
|
+
const spinner = createSpinner('Applying background job files...').start();
|
|
113
|
+
try {
|
|
114
|
+
const result = await this.api.applyV3BackgroundJobFiles(jobId, {
|
|
115
|
+
workspacePath,
|
|
116
|
+
projectPath: workspacePath,
|
|
117
|
+
targetPath: workspacePath,
|
|
118
|
+
});
|
|
119
|
+
spinner.stop();
|
|
120
|
+
if (options.json) {
|
|
121
|
+
console.log(JSON.stringify(result, null, 2));
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
console.log(chalk.green(`${CH.success} Applied ${result.applied.length} file(s) from ${jobId}`));
|
|
125
|
+
for (const file of result.applied.slice(0, 20)) {
|
|
126
|
+
console.log(chalk.gray(` + ${file}`));
|
|
127
|
+
}
|
|
128
|
+
if (result.applied.length > 20) {
|
|
129
|
+
console.log(chalk.gray(` ... and ${result.applied.length - 20} more`));
|
|
130
|
+
}
|
|
131
|
+
if (result.skipped.length > 0) {
|
|
132
|
+
console.log(chalk.yellow(`Skipped ${result.skipped.length} unchanged or unsafe file(s).`));
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
catch (error) {
|
|
136
|
+
spinner.stop();
|
|
137
|
+
this.logger.error(error?.message || String(error));
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
async cancel(jobId, options = {}) {
|
|
141
|
+
if (!jobId) {
|
|
142
|
+
this.logger.error('Usage: vigthoria background cancel <job-id>');
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
const spinner = createSpinner('Cancelling background job...').start();
|
|
146
|
+
try {
|
|
147
|
+
const result = await this.api.cancelV3BackgroundJob(jobId);
|
|
148
|
+
spinner.stop();
|
|
149
|
+
if (options.json) {
|
|
150
|
+
console.log(JSON.stringify(result, null, 2));
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
console.log(chalk.yellow(`${CH.warn} Background job cancelled: ${jobId}`));
|
|
154
|
+
}
|
|
155
|
+
catch (error) {
|
|
156
|
+
spinner.stop();
|
|
157
|
+
this.logger.error(error?.message || String(error));
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
package/dist/commands/chat.js
CHANGED
|
@@ -746,6 +746,7 @@ export class ChatCommand {
|
|
|
746
746
|
.replace(/^\s*(?:json\s*)?\[\s*\{[\s\S]*?"tool"[\s\S]*$/gim, '')
|
|
747
747
|
.replace(/^\s*(?:list_dir|read_file|write_file|edit_file|glob|grep|bash)\s*$/gim, '')
|
|
748
748
|
.replace(/<tool_call>[\s\S]*?<\/tool_call>/gi, '')
|
|
749
|
+
.replace(/<tool_code>[\s\S]*?<\/tool_code>/gi, '')
|
|
749
750
|
.replace(/\n{3,}/g, '\n\n');
|
|
750
751
|
return output;
|
|
751
752
|
}
|
|
@@ -918,6 +919,30 @@ export class ChatCommand {
|
|
|
918
919
|
spinner.text = 'Vigthoria Executor running...';
|
|
919
920
|
return;
|
|
920
921
|
}
|
|
922
|
+
if (event.type === 'model_call_start') {
|
|
923
|
+
if (spinner.isSpinning)
|
|
924
|
+
spinner.stop();
|
|
925
|
+
const model = this.sanitizeServerPath(String(event.model || 'model'));
|
|
926
|
+
const iter = event.iteration ? ` iteration ${event.iteration}` : '';
|
|
927
|
+
const msgCount = Number.isFinite(Number(event.message_count)) ? `, ${event.message_count} messages` : '';
|
|
928
|
+
const toolCount = Number.isFinite(Number(event.tool_count)) ? `, ${event.tool_count} tools available` : '';
|
|
929
|
+
process.stderr.write(chalk.cyan(' [Model] ') + `${model}${iter}: thinking${msgCount}${toolCount}\n`);
|
|
930
|
+
spinner.start();
|
|
931
|
+
spinner.text = `Model ${model} is reasoning...`;
|
|
932
|
+
return;
|
|
933
|
+
}
|
|
934
|
+
if (event.type === 'model_call_complete') {
|
|
935
|
+
if (spinner.isSpinning)
|
|
936
|
+
spinner.stop();
|
|
937
|
+
const model = this.sanitizeServerPath(String(event.model || 'model'));
|
|
938
|
+
const toolCalls = Number.isFinite(Number(event.tool_calls)) ? Number(event.tool_calls) : 0;
|
|
939
|
+
const chars = Number.isFinite(Number(event.content_chars)) ? Number(event.content_chars) : 0;
|
|
940
|
+
const finish = event.finish_reason ? `, ${this.sanitizeServerPath(String(event.finish_reason))}` : '';
|
|
941
|
+
process.stderr.write(chalk.cyan(' [Model] ') + `${model}: produced ${toolCalls} tool call${toolCalls === 1 ? '' : 's'}${chars ? `, ${chars} chars` : ''}${finish}\n`);
|
|
942
|
+
spinner.start();
|
|
943
|
+
spinner.text = toolCalls > 0 ? 'Executing model-selected tools...' : 'Processing model response...';
|
|
944
|
+
return;
|
|
945
|
+
}
|
|
921
946
|
if (event.type === 'executor_error') {
|
|
922
947
|
if (spinner.isSpinning)
|
|
923
948
|
spinner.stop();
|
|
@@ -2245,7 +2270,13 @@ export class ChatCommand {
|
|
|
2245
2270
|
return /^(ja|ja bitte|ja bitte mach das|mach das|bitte mach das|genau|ok|okay|yes|yes please|please do|do it|go ahead|continue|proceed|make it so)$/.test(normalized);
|
|
2246
2271
|
}
|
|
2247
2272
|
taskRequiresWorkspaceChanges(prompt) {
|
|
2248
|
-
|
|
2273
|
+
const text = String(prompt || '').trim();
|
|
2274
|
+
const readOnlyIntent = /\b(analy[sz]e|analyse|analysis|audit|review|inspect|proof|understand|summari[sz]e|scan|read[\s-]?only|where we left|what is|how does|show me|tell me|identify\s+gaps?|gap\s+analysis|production\s+blockers?)\b/i.test(text);
|
|
2275
|
+
const explicitWriteIntent = /\b(build|create|make|implement|complete|fix|repair|edit|modify|write|generate|add|finish|scaffold|develop|update|change|refactor)\b/i.test(text);
|
|
2276
|
+
if (readOnlyIntent && !explicitWriteIntent) {
|
|
2277
|
+
return false;
|
|
2278
|
+
}
|
|
2279
|
+
return explicitWriteIntent && /\b(file|project|game|app|website|html5|frontend|component|feature|code|workspace|repo)\b/i.test(text);
|
|
2249
2280
|
}
|
|
2250
2281
|
getPreviousActionablePrompt() {
|
|
2251
2282
|
if (this.lastActionableUserInput && !this.isConfirmationFollowUp(this.lastActionableUserInput)) {
|
|
@@ -2461,6 +2492,9 @@ export class ChatCommand {
|
|
|
2461
2492
|
if (tid)
|
|
2462
2493
|
liveOutcome.failedTaskIds.add(String(tid));
|
|
2463
2494
|
liveOutcome.executorFailed = true;
|
|
2495
|
+
const err = typeof summary.error === 'string' ? summary.error.trim() : '';
|
|
2496
|
+
if (err && !liveOutcome.executorError)
|
|
2497
|
+
liveOutcome.executorError = err;
|
|
2464
2498
|
}
|
|
2465
2499
|
else if (summary.status === 'completed' || summary.status === 'success') {
|
|
2466
2500
|
if (tid)
|
|
@@ -2603,10 +2637,22 @@ export class ChatCommand {
|
|
|
2603
2637
|
const executorSucceeded = !liveOutcome.executorFailed
|
|
2604
2638
|
&& !liveOutcome.plannerError
|
|
2605
2639
|
&& !liveOutcome.executorError
|
|
2606
|
-
&& workspaceHasOutput
|
|
2607
|
-
&& (!requiresWorkspaceChanges || changedFileCount > 0);
|
|
2640
|
+
&& (requiresWorkspaceChanges ? (workspaceHasOutput && changedFileCount > 0) : true);
|
|
2608
2641
|
if (!executorSucceeded && requiresWorkspaceChanges && changedFileCount === 0 && !liveOutcome.executorError) {
|
|
2609
|
-
|
|
2642
|
+
const clientToolErrors = this.api.getClientToolErrors();
|
|
2643
|
+
const transportErrors = this.api.getLastChatTransportErrors();
|
|
2644
|
+
if (clientToolErrors.length > 0) {
|
|
2645
|
+
liveOutcome.executorError = clientToolErrors[0];
|
|
2646
|
+
}
|
|
2647
|
+
else if (workspaceHasOutput && changedFileCount === 0) {
|
|
2648
|
+
liveOutcome.executorError = 'Files may exist locally but were not tracked by the agent stream. Try /retry or check your workspace path.';
|
|
2649
|
+
}
|
|
2650
|
+
else {
|
|
2651
|
+
liveOutcome.executorError = 'No workspace files were changed for a build/edit request.';
|
|
2652
|
+
}
|
|
2653
|
+
if (transportErrors.length > 0 && !liveOutcome.plannerError) {
|
|
2654
|
+
liveOutcome.plannerError = transportErrors[0];
|
|
2655
|
+
}
|
|
2610
2656
|
}
|
|
2611
2657
|
if (executorSucceeded) {
|
|
2612
2658
|
taskDisplay.complete(1);
|
|
@@ -2618,7 +2664,7 @@ export class ChatCommand {
|
|
|
2618
2664
|
taskDisplay.fail(1, failDetail);
|
|
2619
2665
|
}
|
|
2620
2666
|
// ── Self-healing validation ──────────────────────────────────────
|
|
2621
|
-
if (this.currentProjectPath && !this.jsonOutput && success && executorSucceeded) {
|
|
2667
|
+
if (this.currentProjectPath && !this.jsonOutput && success && executorSucceeded && requiresWorkspaceChanges) {
|
|
2622
2668
|
try {
|
|
2623
2669
|
taskDisplay.start(2, 'validating...');
|
|
2624
2670
|
const healResult = await this.api.runSelfHealingCycle(executionPrompt, this.currentProjectPath, workspaceContext);
|
|
@@ -2651,6 +2697,11 @@ export class ChatCommand {
|
|
|
2651
2697
|
selfHealStatus = 'failed';
|
|
2652
2698
|
}
|
|
2653
2699
|
}
|
|
2700
|
+
else if (!requiresWorkspaceChanges && executorSucceeded) {
|
|
2701
|
+
taskDisplay.complete(2);
|
|
2702
|
+
taskDisplay.skip(3);
|
|
2703
|
+
selfHealStatus = 'skipped';
|
|
2704
|
+
}
|
|
2654
2705
|
else {
|
|
2655
2706
|
taskDisplay.skip(2);
|
|
2656
2707
|
taskDisplay.skip(3);
|
|
@@ -2674,6 +2725,12 @@ export class ChatCommand {
|
|
|
2674
2725
|
selfHealTool,
|
|
2675
2726
|
plannerError: liveOutcome.plannerError ? sanitizeUserFacingErrorText(liveOutcome.plannerError) : null,
|
|
2676
2727
|
executorError: liveOutcome.executorError ? sanitizeUserFacingErrorText(liveOutcome.executorError) : null,
|
|
2728
|
+
clientToolErrors: this.api.getClientToolErrors(),
|
|
2729
|
+
transportErrors: this.api.getLastChatTransportErrors(),
|
|
2730
|
+
workspacePath: workspacePath || null,
|
|
2731
|
+
workspaceSyncIssue: (!executorSucceeded && workspaceHasOutput && changedFileCount === 0)
|
|
2732
|
+
? 'Local workspace has files but the agent did not confirm tracked changes.'
|
|
2733
|
+
: null,
|
|
2677
2734
|
finishedAt: Date.now(),
|
|
2678
2735
|
};
|
|
2679
2736
|
if (!this.jsonOutput && !this.directPromptMode) {
|
|
@@ -2733,6 +2790,10 @@ export class ChatCommand {
|
|
|
2733
2790
|
selfHealTool: null,
|
|
2734
2791
|
plannerError: liveOutcome.plannerError ? sanitizeUserFacingErrorText(liveOutcome.plannerError) : null,
|
|
2735
2792
|
executorError: liveOutcome.executorError ? sanitizeUserFacingErrorText(liveOutcome.executorError) : safeDetail || null,
|
|
2793
|
+
clientToolErrors: this.api.getClientToolErrors(),
|
|
2794
|
+
transportErrors: this.api.getLastChatTransportErrors(),
|
|
2795
|
+
workspacePath: workspacePath || null,
|
|
2796
|
+
workspaceSyncIssue: null,
|
|
2736
2797
|
finishedAt: Date.now(),
|
|
2737
2798
|
};
|
|
2738
2799
|
if (this.jsonOutput) {
|
|
@@ -3095,7 +3156,29 @@ export class ChatCommand {
|
|
|
3095
3156
|
console.log(chalk.gray(' Planner: ') + chalk.red(outcome.plannerError.slice(0, 140)));
|
|
3096
3157
|
}
|
|
3097
3158
|
if (outcome.executorError) {
|
|
3098
|
-
console.log(chalk.gray(' Executor: ') + chalk.red(outcome.executorError.slice(0,
|
|
3159
|
+
console.log(chalk.gray(' Executor: ') + chalk.red(outcome.executorError.slice(0, 240)));
|
|
3160
|
+
}
|
|
3161
|
+
const hasDiagnostics = outcome.clientToolErrors.length > 0
|
|
3162
|
+
|| outcome.transportErrors.length > 0
|
|
3163
|
+
|| outcome.workspaceSyncIssue;
|
|
3164
|
+
if (hasDiagnostics) {
|
|
3165
|
+
console.log('');
|
|
3166
|
+
console.log(chalk.gray('Why this run struggled:'));
|
|
3167
|
+
if (outcome.workspacePath) {
|
|
3168
|
+
console.log(' ' + chalk.white(`Workspace: ${outcome.workspacePath}`));
|
|
3169
|
+
}
|
|
3170
|
+
for (const err of outcome.clientToolErrors.slice(0, 3)) {
|
|
3171
|
+
console.log(' ' + chalk.yellow('Local tools: ') + chalk.white(err.slice(0, 220)));
|
|
3172
|
+
}
|
|
3173
|
+
for (const err of outcome.transportErrors.slice(0, 2)) {
|
|
3174
|
+
console.log(' ' + chalk.yellow('Connectivity: ') + chalk.white(err.slice(0, 220)));
|
|
3175
|
+
}
|
|
3176
|
+
if (outcome.workspaceSyncIssue) {
|
|
3177
|
+
console.log(' ' + chalk.yellow('Sync: ') + chalk.white(outcome.workspaceSyncIssue));
|
|
3178
|
+
}
|
|
3179
|
+
if (outcome.clientToolErrors.some((e) => /no pending client tool call|rejected/i.test(e))) {
|
|
3180
|
+
console.log(' ' + chalk.gray('The agent tried to use your local machine for file tools, but the server timed out waiting. /retry usually works after the SSE bridge fix.'));
|
|
3181
|
+
}
|
|
3099
3182
|
}
|
|
3100
3183
|
console.log('');
|
|
3101
3184
|
console.log(chalk.gray('Result:'));
|
package/dist/index.js
CHANGED
|
@@ -35,6 +35,7 @@ import { HistoryCommand } from './commands/history.js';
|
|
|
35
35
|
import { ReplayCommand } from './commands/replay.js';
|
|
36
36
|
import { ForkCommand } from './commands/fork.js';
|
|
37
37
|
import { CancelCommand } from './commands/cancel.js';
|
|
38
|
+
import { BackgroundCommand } from './commands/background.js';
|
|
38
39
|
import { SecurityCommand } from './commands/security.js';
|
|
39
40
|
import { Config } from './utils/config.js';
|
|
40
41
|
import { Logger, CH } from './utils/logger.js';
|
|
@@ -333,7 +334,7 @@ function isAuthProtectedCommand(command) {
|
|
|
333
334
|
'agent', 'a', 'operator', 'op',
|
|
334
335
|
'edit', 'e', 'generate', 'g', 'explain', 'x', 'fix', 'f', 'review', 'r',
|
|
335
336
|
'workflow', 'flow', 'hub', 'marketplace', 'deploy', 'host', 'preview', 'device',
|
|
336
|
-
'legion', 'history', 'runs', 'replay', 'fork', 'cancel',
|
|
337
|
+
'legion', 'history', 'runs', 'replay', 'fork', 'cancel', 'background', 'bg',
|
|
337
338
|
'repo', 'repository',
|
|
338
339
|
]);
|
|
339
340
|
return protectedCommands.has(command);
|
|
@@ -489,7 +490,7 @@ export async function main(args) {
|
|
|
489
490
|
const isLegionCortexRequest = invokedBinaryName === 'vigthoria' && argv[2] === 'legion' && argv.includes('--cortex');
|
|
490
491
|
if (invokedBinaryName === 'vigthoria-chat') {
|
|
491
492
|
const knownCommands = new Set([
|
|
492
|
-
'chat', 'chat-resume', 'agent', 'edit', 'generate', 'explain', 'fix', 'review', 'cancel',
|
|
493
|
+
'chat', 'chat-resume', 'agent', 'edit', 'generate', 'explain', 'fix', 'review', 'cancel', 'background', 'bg',
|
|
493
494
|
'hub', 'repo', 'deploy', 'operator', 'workflow', 'flow', 'device', 'security', 'vsec', 'login', 'logout', 'status', 'config', 'update',
|
|
494
495
|
'--help', '-h', '--version', '-V', 'help', 'version',
|
|
495
496
|
]);
|
|
@@ -1088,6 +1089,58 @@ Examples:
|
|
|
1088
1089
|
repoCommand.action(() => {
|
|
1089
1090
|
repoCommand.outputHelp();
|
|
1090
1091
|
});
|
|
1092
|
+
// ==================== BACKGROUND AGENT JOBS ====================
|
|
1093
|
+
const backgroundCommand = program
|
|
1094
|
+
.command('background')
|
|
1095
|
+
.alias('bg')
|
|
1096
|
+
.description('Run and manage detached Vigthoria Agent jobs');
|
|
1097
|
+
backgroundCommand
|
|
1098
|
+
.command('start <prompt...>')
|
|
1099
|
+
.description('Start an Agent job in the background and return immediately')
|
|
1100
|
+
.option('--workspace <path>', 'Local workspace path', process.cwd())
|
|
1101
|
+
.option('--json', 'Emit JSON output', false)
|
|
1102
|
+
.action(async (prompt, options) => {
|
|
1103
|
+
const bg = new BackgroundCommand(config, logger);
|
|
1104
|
+
await bg.start(prompt, options);
|
|
1105
|
+
});
|
|
1106
|
+
backgroundCommand
|
|
1107
|
+
.command('list')
|
|
1108
|
+
.alias('ls')
|
|
1109
|
+
.description('List recent background jobs')
|
|
1110
|
+
.option('--limit <n>', 'Maximum jobs to show', '20')
|
|
1111
|
+
.option('--json', 'Emit JSON output', false)
|
|
1112
|
+
.action(async (options) => {
|
|
1113
|
+
const bg = new BackgroundCommand(config, logger);
|
|
1114
|
+
await bg.list({ ...options, limit: Number(options.limit) || 20 });
|
|
1115
|
+
});
|
|
1116
|
+
backgroundCommand
|
|
1117
|
+
.command('status <jobId>')
|
|
1118
|
+
.description('Show background job status')
|
|
1119
|
+
.option('--json', 'Emit JSON output', false)
|
|
1120
|
+
.action(async (jobId, options) => {
|
|
1121
|
+
const bg = new BackgroundCommand(config, logger);
|
|
1122
|
+
await bg.status(jobId, options);
|
|
1123
|
+
});
|
|
1124
|
+
backgroundCommand
|
|
1125
|
+
.command('apply <jobId>')
|
|
1126
|
+
.description('Apply completed background job file changes to the local workspace')
|
|
1127
|
+
.option('--workspace <path>', 'Local workspace path', process.cwd())
|
|
1128
|
+
.option('--json', 'Emit JSON output', false)
|
|
1129
|
+
.action(async (jobId, options) => {
|
|
1130
|
+
const bg = new BackgroundCommand(config, logger);
|
|
1131
|
+
await bg.apply(jobId, options);
|
|
1132
|
+
});
|
|
1133
|
+
backgroundCommand
|
|
1134
|
+
.command('cancel <jobId>')
|
|
1135
|
+
.description('Cancel a running background job')
|
|
1136
|
+
.option('--json', 'Emit JSON output', false)
|
|
1137
|
+
.action(async (jobId, options) => {
|
|
1138
|
+
const bg = new BackgroundCommand(config, logger);
|
|
1139
|
+
await bg.cancel(jobId, options);
|
|
1140
|
+
});
|
|
1141
|
+
backgroundCommand.action(() => {
|
|
1142
|
+
backgroundCommand.outputHelp();
|
|
1143
|
+
});
|
|
1091
1144
|
// ==================== DEPLOY COMMANDS ====================
|
|
1092
1145
|
// Deploy command - Host projects on Vigthoria
|
|
1093
1146
|
const deployCommand = program
|
package/dist/utils/api.d.ts
CHANGED
|
@@ -224,6 +224,11 @@ export declare class APIClient {
|
|
|
224
224
|
private vigFlowTokens;
|
|
225
225
|
private _httpsAgent;
|
|
226
226
|
private lastChatTransportErrors;
|
|
227
|
+
private clientToolErrors;
|
|
228
|
+
private pendingV3ClientToolTasks;
|
|
229
|
+
/** Tracks files mutated via client_tool_request during an active V3 SSE stream. */
|
|
230
|
+
private activeV3StreamedFiles;
|
|
231
|
+
private activeV3StreamContext;
|
|
227
232
|
constructor(config: Config, logger: Logger);
|
|
228
233
|
/**
|
|
229
234
|
* Destroy keep-alive sockets so the Node.js event loop can drain
|
|
@@ -253,6 +258,7 @@ export declare class APIClient {
|
|
|
253
258
|
getV3AgentBaseUrls(preferLocal?: boolean): string[];
|
|
254
259
|
getV3AgentRunUrl(baseUrl: string): string;
|
|
255
260
|
getV3AgentContinueUrl(baseUrl: string): string;
|
|
261
|
+
getV3AgentBackgroundUrl(baseUrl: string, suffix?: string): string;
|
|
256
262
|
getOperatorBaseUrls(): string[];
|
|
257
263
|
getOperatorStreamUrl(baseUrl: string): string;
|
|
258
264
|
getMcpBaseUrls(): string[];
|
|
@@ -355,6 +361,10 @@ export declare class APIClient {
|
|
|
355
361
|
extractExpectedWorkspaceFiles(message?: string, context?: Record<string, any>): string[];
|
|
356
362
|
captureV3AgentStreamMutation(event: any, streamedFiles: Record<string, string>, serverRoot?: string | null): void;
|
|
357
363
|
private applyV3AgentStreamEventToWorkspace;
|
|
364
|
+
private resolveV3ClientToolPath;
|
|
365
|
+
private recordV3ClientToolMutation;
|
|
366
|
+
private executeV3ClientToolRequest;
|
|
367
|
+
private handleV3ClientToolRequest;
|
|
358
368
|
private writeV3AgentWorkspaceFile;
|
|
359
369
|
private deleteV3AgentWorkspaceFile;
|
|
360
370
|
recoverAgentWorkspaceFiles(context?: Record<string, any>, streamedFiles?: Record<string, string>, expectedFiles?: string[]): void;
|
|
@@ -374,8 +384,25 @@ export declare class APIClient {
|
|
|
374
384
|
*/
|
|
375
385
|
private synthesizeAnswerFromV3Events;
|
|
376
386
|
private sanitizeV3AgentEventForUser;
|
|
387
|
+
private resolveAgentChangedFiles;
|
|
388
|
+
private finalizeV3AgentWorkflowResponse;
|
|
377
389
|
collectV3AgentStream(response: Response, context?: Record<string, any>): Promise<any>;
|
|
378
390
|
runV3AgentWorkflow(message: string, context?: Record<string, any>): Promise<V3AgentWorkflowResponse>;
|
|
391
|
+
startV3BackgroundJob(message: string, context?: Record<string, any>): Promise<any>;
|
|
392
|
+
listV3BackgroundJobs(limit?: number): Promise<any[]>;
|
|
393
|
+
getV3BackgroundJob(jobId: string): Promise<any>;
|
|
394
|
+
cancelV3BackgroundJob(jobId: string): Promise<any>;
|
|
395
|
+
getV3BackgroundJobFiles(jobId: string): Promise<{
|
|
396
|
+
status: string;
|
|
397
|
+
files: Record<string, string>;
|
|
398
|
+
file_count: number;
|
|
399
|
+
local_workspace_path?: string;
|
|
400
|
+
}>;
|
|
401
|
+
applyV3BackgroundJobFiles(jobId: string, context?: Record<string, any>): Promise<{
|
|
402
|
+
applied: string[];
|
|
403
|
+
skipped: string[];
|
|
404
|
+
status: string;
|
|
405
|
+
}>;
|
|
379
406
|
private formatOperatorResponse;
|
|
380
407
|
runOperatorWorkflow(message: string, context?: Record<string, any>): Promise<OperatorWorkflowResponse>;
|
|
381
408
|
/**
|
|
@@ -515,6 +542,9 @@ export declare class APIClient {
|
|
|
515
542
|
}>;
|
|
516
543
|
mapPreflightEndpointToRoute(endpoint: string): ChatRoutePreference | null;
|
|
517
544
|
getLastChatTransportErrors(): string[];
|
|
545
|
+
getClientToolErrors(): string[];
|
|
546
|
+
clearAgentRunDiagnostics(): void;
|
|
547
|
+
private recordClientToolError;
|
|
518
548
|
submitClientToolResult(contextId: string, callId: string, result: {
|
|
519
549
|
success: boolean;
|
|
520
550
|
output: string;
|