vigthoria-cli 1.11.2 → 1.11.4
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 +1 -0
- package/dist/commands/background.js +55 -1
- package/dist/commands/chat.d.ts +4 -0
- package/dist/commands/chat.js +102 -8
- package/dist/index.js +4 -0
- package/dist/utils/api.js +4 -2
- package/dist/utils/session.d.ts +1 -0
- package/package.json +1 -1
- package/scripts/release/validate-no-go-gates.sh +1 -1
|
@@ -15,5 +15,6 @@ export declare class BackgroundCommand {
|
|
|
15
15
|
status(jobId: string, options?: BackgroundOptions): Promise<void>;
|
|
16
16
|
apply(jobId: string, options?: BackgroundOptions): Promise<void>;
|
|
17
17
|
cancel(jobId: string, options?: BackgroundOptions): Promise<void>;
|
|
18
|
+
private extractBackgroundOutcome;
|
|
18
19
|
}
|
|
19
20
|
export {};
|
|
@@ -82,8 +82,9 @@ export class BackgroundCommand {
|
|
|
82
82
|
try {
|
|
83
83
|
const job = await this.api.getV3BackgroundJob(jobId);
|
|
84
84
|
spinner.stop();
|
|
85
|
+
const outcome = this.extractBackgroundOutcome(job);
|
|
85
86
|
if (options.json) {
|
|
86
|
-
console.log(JSON.stringify(job, null, 2));
|
|
87
|
+
console.log(JSON.stringify({ ...job, outcomeTruth: outcome }, null, 2));
|
|
87
88
|
return;
|
|
88
89
|
}
|
|
89
90
|
console.log(chalk.bold(`\nBackground Job ${chalk.cyan(job.job_id)}\n`));
|
|
@@ -91,6 +92,12 @@ export class BackgroundCommand {
|
|
|
91
92
|
console.log(`Files: ${job.file_count || 0}`);
|
|
92
93
|
console.log(`Updated: ${job.updated_at || '-'}`);
|
|
93
94
|
console.log(`Workspace: ${job.local_workspace_path || job.workspace_name || '-'}`);
|
|
95
|
+
if (outcome.tasksTotal > 0 || outcome.tasksCompleted > 0) {
|
|
96
|
+
console.log(`Tasks: ${outcome.tasksCompleted}/${outcome.tasksTotal}${outcome.success === true ? chalk.green(' (complete)') : outcome.success === false ? chalk.red(' (incomplete)') : ''}`);
|
|
97
|
+
}
|
|
98
|
+
if (outcome.headline) {
|
|
99
|
+
console.log(chalk.gray(`Outcome: ${outcome.headline}`));
|
|
100
|
+
}
|
|
94
101
|
if (job.error)
|
|
95
102
|
console.log(chalk.red(`Error: ${job.error}`));
|
|
96
103
|
console.log(chalk.gray(`\n${String(job.request || '').slice(0, 500)}`));
|
|
@@ -157,4 +164,51 @@ export class BackgroundCommand {
|
|
|
157
164
|
this.logger.error(error?.message || String(error));
|
|
158
165
|
}
|
|
159
166
|
}
|
|
167
|
+
extractBackgroundOutcome(job) {
|
|
168
|
+
const result = (job?.result && typeof job.result === 'object') ? job.result : {};
|
|
169
|
+
const events = Array.isArray(job?.events) ? job.events : [];
|
|
170
|
+
let tasksCompleted = Number(result.tasks_completed ?? result.tasksCompleted ?? 0);
|
|
171
|
+
let tasksTotal = Number(result.tasks_total ?? result.tasksTotal ?? 0);
|
|
172
|
+
let success = typeof result.success === 'boolean' ? result.success : null;
|
|
173
|
+
for (const event of events) {
|
|
174
|
+
if (!event || typeof event !== 'object')
|
|
175
|
+
continue;
|
|
176
|
+
if (event.type === 'result' || event.event === 'result') {
|
|
177
|
+
const payload = event.data || event.payload || event;
|
|
178
|
+
if (payload && typeof payload === 'object') {
|
|
179
|
+
if (payload.tasks_completed != null)
|
|
180
|
+
tasksCompleted = Number(payload.tasks_completed);
|
|
181
|
+
if (payload.tasksCompleted != null)
|
|
182
|
+
tasksCompleted = Number(payload.tasksCompleted);
|
|
183
|
+
if (payload.tasks_total != null)
|
|
184
|
+
tasksTotal = Number(payload.tasks_total);
|
|
185
|
+
if (payload.tasksTotal != null)
|
|
186
|
+
tasksTotal = Number(payload.tasksTotal);
|
|
187
|
+
if (typeof payload.success === 'boolean')
|
|
188
|
+
success = payload.success;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
if (success == null && tasksTotal > 0) {
|
|
193
|
+
success = tasksCompleted >= tasksTotal;
|
|
194
|
+
}
|
|
195
|
+
if (success == null && job?.status === 'completed') {
|
|
196
|
+
success = true;
|
|
197
|
+
}
|
|
198
|
+
if (success == null && job?.status === 'failed') {
|
|
199
|
+
success = false;
|
|
200
|
+
}
|
|
201
|
+
let headline = '';
|
|
202
|
+
if (tasksTotal > 0) {
|
|
203
|
+
headline = success === true
|
|
204
|
+
? `All ${tasksTotal} task(s) completed`
|
|
205
|
+
: success === false
|
|
206
|
+
? `${tasksCompleted}/${tasksTotal} task(s) completed`
|
|
207
|
+
: `${tasksCompleted}/${tasksTotal} task(s) reported`;
|
|
208
|
+
}
|
|
209
|
+
else if (typeof result.message === 'string' && result.message.trim()) {
|
|
210
|
+
headline = result.message.trim();
|
|
211
|
+
}
|
|
212
|
+
return { tasksCompleted, tasksTotal, success, headline };
|
|
213
|
+
}
|
|
160
214
|
}
|
package/dist/commands/chat.d.ts
CHANGED
|
@@ -17,6 +17,8 @@ interface ChatOptions {
|
|
|
17
17
|
json?: boolean;
|
|
18
18
|
bridge?: string;
|
|
19
19
|
grant?: boolean;
|
|
20
|
+
retry?: boolean;
|
|
21
|
+
continue?: boolean;
|
|
20
22
|
}
|
|
21
23
|
export declare class ChatCommand {
|
|
22
24
|
private config;
|
|
@@ -147,6 +149,8 @@ export declare class ChatCommand {
|
|
|
147
149
|
private runOperatorDirectAnswer;
|
|
148
150
|
private runSimplePrompt;
|
|
149
151
|
private runAgentTurn;
|
|
152
|
+
private buildLocalLoopLiveOutcome;
|
|
153
|
+
private persistLocalLoopOutcome;
|
|
150
154
|
private runLocalAgentLoop;
|
|
151
155
|
private primeBypassedTargetFileContext;
|
|
152
156
|
private tryDirectSingleFileFlow;
|
package/dist/commands/chat.js
CHANGED
|
@@ -477,6 +477,10 @@ export class ChatCommand {
|
|
|
477
477
|
*/
|
|
478
478
|
isOperatorDirectAnswerable(prompt) {
|
|
479
479
|
const trimmed = prompt.trim();
|
|
480
|
+
// Infrastructure status pings are never repo-grounded analysis.
|
|
481
|
+
if (/^(status(\s+check)?|health(\s+check)?|ping)$/i.test(trimmed)) {
|
|
482
|
+
return true;
|
|
483
|
+
}
|
|
480
484
|
// ── Exclusion guard: any prompt that references code artefacts,
|
|
481
485
|
// file paths, or analysis verbs MUST go through a tool-backed path
|
|
482
486
|
// (BMAD or agent loop), never the toolless direct-answer shortcut.
|
|
@@ -711,6 +715,9 @@ export class ChatCommand {
|
|
|
711
715
|
}
|
|
712
716
|
}
|
|
713
717
|
writeV3StreamText(spinner, text) {
|
|
718
|
+
if (this.jsonOutput) {
|
|
719
|
+
return;
|
|
720
|
+
}
|
|
714
721
|
const safeText = this.sanitizeV3VisibleStreamText(this.sanitizeServerPath(text));
|
|
715
722
|
if (!safeText) {
|
|
716
723
|
return;
|
|
@@ -1137,14 +1144,14 @@ export class ChatCommand {
|
|
|
1137
1144
|
}
|
|
1138
1145
|
console.log(chalk.green(`Using workspace: ${this.currentProjectPath}`));
|
|
1139
1146
|
}
|
|
1140
|
-
if (this.jsonOutput && !options.prompt) {
|
|
1141
|
-
throw new Error('--json is only supported together with --prompt.');
|
|
1147
|
+
if (this.jsonOutput && !options.prompt && !options.retry && !options.continue) {
|
|
1148
|
+
throw new Error('--json is only supported together with --prompt, --retry, or --continue.');
|
|
1142
1149
|
}
|
|
1143
1150
|
this.ensureProjectWorkspace();
|
|
1144
1151
|
this.directPromptMode = Boolean(options.prompt);
|
|
1145
1152
|
this.directToolContinuationCount = 0;
|
|
1146
1153
|
this.tools = new AgenticTools(this.logger, this.currentProjectPath, async (action) => this.requestPermission(action), this.autoApprove);
|
|
1147
|
-
this.initializeSession(options.resume === true);
|
|
1154
|
+
this.initializeSession(options.resume === true || options.retry === true || options.continue === true);
|
|
1148
1155
|
// ── Commando Bridge: connect if --bridge was specified ──────────
|
|
1149
1156
|
if (options.bridge) {
|
|
1150
1157
|
const bridgeClient = new BridgeClient({
|
|
@@ -1169,6 +1176,18 @@ export class ChatCommand {
|
|
|
1169
1176
|
this.logger.error(this.operatorAccessMessage());
|
|
1170
1177
|
return;
|
|
1171
1178
|
}
|
|
1179
|
+
if (options.retry || options.continue) {
|
|
1180
|
+
if (!this.agentMode) {
|
|
1181
|
+
throw new Error('--retry and --continue require agent mode.');
|
|
1182
|
+
}
|
|
1183
|
+
const followUp = options.retry ? this.buildRetryPrompt() : this.buildContinuePrompt();
|
|
1184
|
+
if (!followUp) {
|
|
1185
|
+
throw new Error('No previous agent run to retry or continue. Run an agent prompt first with the same --project, or use --resume.');
|
|
1186
|
+
}
|
|
1187
|
+
this.directPromptMode = true;
|
|
1188
|
+
await this.runAgentTurn(followUp);
|
|
1189
|
+
return;
|
|
1190
|
+
}
|
|
1172
1191
|
if (options.prompt) {
|
|
1173
1192
|
const bridgePromptTimeoutMs = (() => {
|
|
1174
1193
|
const rawValue = process.env.VIGTHORIA_BRIDGE_PROMPT_TIMEOUT_MS || process.env.V3_BRIDGE_PROMPT_TIMEOUT_MS;
|
|
@@ -1404,6 +1423,9 @@ export class ChatCommand {
|
|
|
1404
1423
|
this.agentMode = this.currentSession.agentMode || this.agentMode;
|
|
1405
1424
|
this.operatorMode = this.currentSession.operatorMode || this.operatorMode;
|
|
1406
1425
|
this.currentModel = this.currentSession.model || this.currentModel;
|
|
1426
|
+
if (this.currentSession.lastAgentRunOutcome) {
|
|
1427
|
+
this.lastAgentRunOutcome = this.currentSession.lastAgentRunOutcome;
|
|
1428
|
+
}
|
|
1407
1429
|
return;
|
|
1408
1430
|
}
|
|
1409
1431
|
}
|
|
@@ -1918,6 +1940,42 @@ export class ChatCommand {
|
|
|
1918
1940
|
}
|
|
1919
1941
|
await this.runLocalAgentLoop(prompt);
|
|
1920
1942
|
}
|
|
1943
|
+
buildLocalLoopLiveOutcome(prompt) {
|
|
1944
|
+
const liveOutcome = createLiveOutcome();
|
|
1945
|
+
liveOutcome.requiresWorkspaceChanges = this.taskRequiresWorkspaceChanges(prompt);
|
|
1946
|
+
liveOutcome.analysisToolsUsed = this.agentToolEvidence.discovery;
|
|
1947
|
+
liveOutcome.changedFileCount = this.agentToolEvidence.mutation;
|
|
1948
|
+
liveOutcome.workspaceHasOutput = this.agentToolEvidence.mutation > 0;
|
|
1949
|
+
if (this.agentToolEvidence.searchFailed > 0 && this.agentToolEvidence.discovery === 0) {
|
|
1950
|
+
liveOutcome.executorFailed = true;
|
|
1951
|
+
liveOutcome.executorError = 'Search tools failed before gathering workspace evidence';
|
|
1952
|
+
}
|
|
1953
|
+
return liveOutcome;
|
|
1954
|
+
}
|
|
1955
|
+
persistLocalLoopOutcome(prompt, evaluation, liveOutcome) {
|
|
1956
|
+
this.lastAgentRunOutcome = {
|
|
1957
|
+
prompt,
|
|
1958
|
+
taskId: null,
|
|
1959
|
+
contextId: null,
|
|
1960
|
+
tasksSucceeded: liveOutcome.tasksSucceeded,
|
|
1961
|
+
tasksTotal: liveOutcome.tasksTotal,
|
|
1962
|
+
failedTaskIds: [...liveOutcome.failedTaskIds],
|
|
1963
|
+
unfinishedTaskIds: [],
|
|
1964
|
+
qualityScore: null,
|
|
1965
|
+
qualityMissing: [],
|
|
1966
|
+
qualityBlockers: evaluation.executorSucceeded ? [] : [evaluation.statusHeadline],
|
|
1967
|
+
hasOutput: liveOutcome.workspaceHasOutput,
|
|
1968
|
+
selfHealStatus: 'skipped',
|
|
1969
|
+
selfHealTool: null,
|
|
1970
|
+
plannerError: null,
|
|
1971
|
+
executorError: liveOutcome.executorError,
|
|
1972
|
+
clientToolErrors: [],
|
|
1973
|
+
transportErrors: [],
|
|
1974
|
+
workspacePath: this.currentProjectPath || null,
|
|
1975
|
+
workspaceSyncIssue: null,
|
|
1976
|
+
finishedAt: Date.now(),
|
|
1977
|
+
};
|
|
1978
|
+
}
|
|
1921
1979
|
async runLocalAgentLoop(prompt) {
|
|
1922
1980
|
if (!this.tools) {
|
|
1923
1981
|
throw new Error('Agent tools are not initialized.');
|
|
@@ -1953,14 +2011,26 @@ export class ChatCommand {
|
|
|
1953
2011
|
const evidenceSummary = this.synthesizeEvidenceFromHistory();
|
|
1954
2012
|
if (evidenceSummary) {
|
|
1955
2013
|
const fallbackContent = this.sanitizeDirectModeOutput(evidenceSummary);
|
|
2014
|
+
const liveOutcome = this.buildLocalLoopLiveOutcome(prompt);
|
|
2015
|
+
const evaluation = evaluateExecutorSuccess(liveOutcome);
|
|
2016
|
+
this.persistLocalLoopOutcome(prompt, evaluation, liveOutcome);
|
|
1956
2017
|
if (this.jsonOutput) {
|
|
2018
|
+
process.exitCode = evaluation.executorSucceeded ? 0 : 1;
|
|
1957
2019
|
console.log(JSON.stringify({
|
|
1958
|
-
success:
|
|
2020
|
+
success: evaluation.executorSucceeded,
|
|
1959
2021
|
mode: 'agent',
|
|
1960
2022
|
model: this.currentModel,
|
|
1961
|
-
partial:
|
|
2023
|
+
partial: !evaluation.executorSucceeded,
|
|
1962
2024
|
content: fallbackContent,
|
|
1963
|
-
|
|
2025
|
+
statusHeadline: evaluation.statusHeadline,
|
|
2026
|
+
metadata: {
|
|
2027
|
+
executionPath: 'local-agent-loop',
|
|
2028
|
+
recovered: true,
|
|
2029
|
+
outcomeTruth: {
|
|
2030
|
+
executorSucceeded: evaluation.executorSucceeded,
|
|
2031
|
+
uiTheme: evaluation.uiTheme,
|
|
2032
|
+
},
|
|
2033
|
+
},
|
|
1964
2034
|
}, null, 2));
|
|
1965
2035
|
}
|
|
1966
2036
|
else {
|
|
@@ -2056,15 +2126,26 @@ export class ChatCommand {
|
|
|
2056
2126
|
continue;
|
|
2057
2127
|
}
|
|
2058
2128
|
const finalContent = this.resolveDirectModeCompletion(prompt, visibleText);
|
|
2129
|
+
const liveOutcome = this.buildLocalLoopLiveOutcome(prompt);
|
|
2130
|
+
const evaluation = evaluateExecutorSuccess(liveOutcome);
|
|
2131
|
+
this.persistLocalLoopOutcome(prompt, evaluation, liveOutcome);
|
|
2059
2132
|
if (this.jsonOutput) {
|
|
2133
|
+
process.exitCode = evaluation.executorSucceeded ? 0 : 1;
|
|
2060
2134
|
console.log(JSON.stringify({
|
|
2061
|
-
success:
|
|
2135
|
+
success: evaluation.executorSucceeded,
|
|
2062
2136
|
mode: 'agent',
|
|
2063
2137
|
model: this.currentModel,
|
|
2064
|
-
partial:
|
|
2138
|
+
partial: !evaluation.executorSucceeded,
|
|
2065
2139
|
content: finalContent,
|
|
2140
|
+
statusHeadline: evaluation.statusHeadline,
|
|
2066
2141
|
metadata: {
|
|
2067
2142
|
executionPath: 'local-agent-loop',
|
|
2143
|
+
outcomeTruth: {
|
|
2144
|
+
executorSucceeded: evaluation.executorSucceeded,
|
|
2145
|
+
uiTheme: evaluation.uiTheme,
|
|
2146
|
+
analysisToolsUsed: liveOutcome.analysisToolsUsed,
|
|
2147
|
+
changedFileCount: liveOutcome.changedFileCount,
|
|
2148
|
+
},
|
|
2068
2149
|
},
|
|
2069
2150
|
}, null, 2));
|
|
2070
2151
|
}
|
|
@@ -2109,6 +2190,13 @@ export class ChatCommand {
|
|
|
2109
2190
|
return;
|
|
2110
2191
|
}
|
|
2111
2192
|
}
|
|
2193
|
+
const liveOutcome = this.buildLocalLoopLiveOutcome(prompt);
|
|
2194
|
+
const exhaustedEval = evaluateExecutorSuccess({
|
|
2195
|
+
...liveOutcome,
|
|
2196
|
+
executorFailed: true,
|
|
2197
|
+
executorError: 'Agent exhausted the maximum local tool loop turns before reaching a clean completion.',
|
|
2198
|
+
});
|
|
2199
|
+
this.persistLocalLoopOutcome(prompt, exhaustedEval, liveOutcome);
|
|
2112
2200
|
if (this.jsonOutput) {
|
|
2113
2201
|
process.exitCode = 1;
|
|
2114
2202
|
console.log(JSON.stringify({
|
|
@@ -2118,8 +2206,13 @@ export class ChatCommand {
|
|
|
2118
2206
|
partial: true,
|
|
2119
2207
|
content: 'Task complete.',
|
|
2120
2208
|
error: 'Agent exhausted the maximum local tool loop turns before reaching a clean completion.',
|
|
2209
|
+
statusHeadline: exhaustedEval.statusHeadline,
|
|
2121
2210
|
metadata: {
|
|
2122
2211
|
executionPath: 'local-agent-loop',
|
|
2212
|
+
outcomeTruth: {
|
|
2213
|
+
executorSucceeded: false,
|
|
2214
|
+
uiTheme: exhaustedEval.uiTheme,
|
|
2215
|
+
},
|
|
2123
2216
|
},
|
|
2124
2217
|
}, null, 2));
|
|
2125
2218
|
}
|
|
@@ -4150,6 +4243,7 @@ export class ChatCommand {
|
|
|
4150
4243
|
this.currentSession.agentMode = this.agentMode;
|
|
4151
4244
|
this.currentSession.operatorMode = this.operatorMode;
|
|
4152
4245
|
this.currentSession.messages = [...this.messages];
|
|
4246
|
+
this.currentSession.lastAgentRunOutcome = this.lastAgentRunOutcome;
|
|
4153
4247
|
this.currentSession = this.sessionManager.compactInMemory(this.currentSession);
|
|
4154
4248
|
this.messages = [...this.currentSession.messages];
|
|
4155
4249
|
this.sessionManager.save(this.currentSession);
|
package/dist/index.js
CHANGED
|
@@ -614,6 +614,8 @@ export async function main(args) {
|
|
|
614
614
|
.option('--prompt <text>', 'Run a single agent prompt directly and exit')
|
|
615
615
|
.option('-w, --workflow <selector>', 'Run the prompt through a named or explicit VigFlow workflow target')
|
|
616
616
|
.option('--json', 'Emit machine-readable JSON output for direct prompt runs', false)
|
|
617
|
+
.option('--retry', 'Retry failed tasks from the last agent run in this workspace session', false)
|
|
618
|
+
.option('--continue', 'Continue unfinished tasks from the last agent run in this workspace session', false)
|
|
617
619
|
.option('--auto-approve', 'Auto-approve all actions (dangerous!)', false)
|
|
618
620
|
.option('--bridge <url>', 'Connect to Vigthoria Commando Bridge for remote admin observability')
|
|
619
621
|
.action(async (options) => {
|
|
@@ -630,6 +632,8 @@ export async function main(args) {
|
|
|
630
632
|
autoApprove: options.autoApprove,
|
|
631
633
|
prompt: options.prompt,
|
|
632
634
|
bridge: options.bridge,
|
|
635
|
+
retry: options.retry,
|
|
636
|
+
continue: options.continue,
|
|
633
637
|
});
|
|
634
638
|
});
|
|
635
639
|
program
|
package/dist/utils/api.js
CHANGED
|
@@ -1648,6 +1648,8 @@ export class APIClient {
|
|
|
1648
1648
|
const serverWorkspacePath = this.resolveServerBindableWorkspacePath(resolvedContext);
|
|
1649
1649
|
const localWorkspaceName = this.getDisplayWorkspaceName(targetPath);
|
|
1650
1650
|
const localWorkspaceRef = localWorkspaceName ? `vigthoria://local-workspace/${localWorkspaceName}` : null;
|
|
1651
|
+
const rawBrain = resolvedContext.vigthoriaBrain || resolvedContext.vigthoria_brain || null;
|
|
1652
|
+
const dedupedBrain = rawBrain ? this.dedupeBrainPayload(rawBrain) : null;
|
|
1651
1653
|
return JSON.stringify({
|
|
1652
1654
|
workspace: this.buildPublicWorkspaceDescriptor(resolvedContext.workspace, {
|
|
1653
1655
|
localWorkspacePath: targetPath,
|
|
@@ -1681,8 +1683,8 @@ export class APIClient {
|
|
|
1681
1683
|
contextId: resolvedContext.contextId,
|
|
1682
1684
|
traceId: resolvedContext.traceId,
|
|
1683
1685
|
requestStartedAt: resolvedContext.requestStartedAt,
|
|
1684
|
-
vigthoriaBrain:
|
|
1685
|
-
vigthoria_brain:
|
|
1686
|
+
vigthoriaBrain: dedupedBrain,
|
|
1687
|
+
vigthoria_brain: dedupedBrain,
|
|
1686
1688
|
});
|
|
1687
1689
|
}
|
|
1688
1690
|
extractEmergencyAppName(message = '', fallback = 'Signal Desk') {
|
package/dist/utils/session.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -76,7 +76,7 @@ $CLI hyper-loop status >/tmp/vig-hyperloop.txt
|
|
|
76
76
|
$CLI devtools connect >/tmp/vig-devtools.txt
|
|
77
77
|
|
|
78
78
|
echo "[6.11] operator flow"
|
|
79
|
-
$CLI operator --prompt "
|
|
79
|
+
$CLI operator --prompt "reply with exactly: OK" --json >/tmp/vig-operator.json
|
|
80
80
|
python3 - << 'PY'
|
|
81
81
|
import json
|
|
82
82
|
j=json.load(open('/tmp/vig-operator.json'))
|