vigthoria-cli 1.13.26 → 1.13.29
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 +73 -26
- package/dist/commands/config.js +4 -4
- package/dist/commands/fork.d.ts +3 -2
- package/dist/commands/fork.js +124 -123
- package/dist/commands/game.d.ts +8 -0
- package/dist/commands/game.js +113 -9
- package/dist/commands/history.d.ts +0 -1
- package/dist/commands/history.js +8 -22
- package/dist/commands/hub.d.ts +20 -0
- package/dist/commands/hub.js +17 -3
- package/dist/commands/preview.js +7 -2
- package/dist/commands/product-run-registration.js +1 -1
- package/dist/commands/replay.d.ts +0 -1
- package/dist/commands/replay.js +10 -19
- package/dist/commands/repo.js +16 -4
- package/dist/commands/update-registration.js +2 -2
- package/dist/commands/workflow.d.ts +4 -0
- package/dist/commands/workflow.js +27 -0
- package/dist/index.js +6 -4
- package/dist/utils/agentRunOutcome.d.ts +7 -0
- package/dist/utils/agentRunOutcome.js +13 -0
- package/dist/utils/api.d.ts +20 -5
- package/dist/utils/api.js +428 -43
- package/dist/utils/command-policy.js +1 -1
- package/dist/utils/config.d.ts +2 -0
- package/dist/utils/config.js +8 -3
- package/dist/utils/frontend-preview-service.d.ts +1 -0
- package/dist/utils/frontend-preview-service.js +54 -5
- package/dist/utils/model-governance.js +23 -14
- package/dist/utils/model-transport-service.js +1 -1
- package/dist/utils/network-policy.js +15 -3
- package/dist/utils/operator-client.js +23 -4
- package/dist/utils/post-write-validator.js +7 -3
- package/dist/utils/preview-screenshot-adapter.d.ts +16 -41
- package/dist/utils/preview-screenshot-adapter.js +273 -64
- package/dist/utils/runtime-capability.d.ts +7 -0
- package/dist/utils/runtime-capability.js +11 -0
- package/dist/utils/runtime-temp.d.ts +5 -2
- package/dist/utils/runtime-temp.js +125 -29
- package/dist/utils/tools.js +1 -1
- package/dist/utils/v3-stream-events.js +10 -2
- package/dist/utils/v3-workspace-service.d.ts +1 -0
- package/dist/utils/v3-workspace-service.js +38 -1
- package/dist/utils/vigflow-client.d.ts +9 -0
- package/dist/utils/vigflow-client.js +48 -2
- package/dist/utils/workspace-reference.d.ts +8 -0
- package/dist/utils/workspace-reference.js +21 -0
- package/package.json +4 -6
- package/scripts/release/LOCAL_MACHINE_USER_VERIFICATION.md +2 -2
- package/scripts/release/validate-live-service-gates.sh +3 -3
- package/scripts/release/validate-no-go-gates.sh +2 -0
package/dist/commands/chat.js
CHANGED
|
@@ -22,7 +22,7 @@ import { renderDynamicHelp } from '../utils/command-menu.js';
|
|
|
22
22
|
import { resolvePromptWorkspace } from '../utils/prompt-workspace-resolver.js';
|
|
23
23
|
import { FileUtils } from '../utils/files.js';
|
|
24
24
|
import { isDirectModeFollowUpQuestion, sanitizeDirectModeOutput, stripHiddenThoughtBlocks } from '../utils/direct-output-policy.js';
|
|
25
|
-
import { createLiveOutcome, evaluateExecutorSuccess, handleRunCompleteEvent, handleTaskEvent, isSubstantiveAgentAnswer, isToolEvidenceStubAnswer, normalizeAgentAnswerContent, noteAnalysisToolUse, } from '../utils/agentRunOutcome.js';
|
|
25
|
+
import { createLiveOutcome, evaluateExecutorSuccess, handleRunCompleteEvent, handleTaskEvent, isSubstantiveAgentAnswer, isToolEvidenceStubAnswer, normalizeAgentAnswerContent, noteAnalysisToolUse, resolveAgentPartialMutation, } from '../utils/agentRunOutcome.js';
|
|
26
26
|
import { looksLikeMarkdownReport, renderMarkdownToTerminal, summarizeMarkdownReport, } from '../utils/terminalMarkdown.js';
|
|
27
27
|
import { emitDeckEvent, isDeckModeEnabled } from '../utils/deckEvents.js';
|
|
28
28
|
import { formatGoaSystemGrounding, splitGoaContextFromInput, } from '../utils/goaEvents.js';
|
|
@@ -30,6 +30,7 @@ import { inferAgentTaskTypeWithContext, resolvePlannerAgentTimeoutMs, resolveWor
|
|
|
30
30
|
import { resolveAgentRoute } from '../utils/agentRoute.js';
|
|
31
31
|
import { isV3StreamKeepaliveEvent } from '../utils/v3-stream-events.js';
|
|
32
32
|
import { resolveAutoApproval } from '../utils/process-policy.js';
|
|
33
|
+
import { hasLocalV3ServiceIdentity } from '../utils/runtime-capability.js';
|
|
33
34
|
import { ChatToolCallParser } from '../utils/chat-tool-call-parser.js';
|
|
34
35
|
import { ChatPromptPolicy } from '../utils/chat-prompt-policy.js';
|
|
35
36
|
import { AgentStreamState } from '../utils/agent-stream-state.js';
|
|
@@ -1333,17 +1334,18 @@ export class ChatCommand {
|
|
|
1333
1334
|
isJsonOutput: () => this.jsonOutput,
|
|
1334
1335
|
idleTimeoutMs: () => DEFAULT_V3_AGENT_IDLE_TIMEOUT_MS,
|
|
1335
1336
|
});
|
|
1336
|
-
this.sessionManager = new SessionManager();
|
|
1337
|
+
this.sessionManager = new SessionManager(this.config.getStateRoot());
|
|
1337
1338
|
}
|
|
1338
1339
|
async run(options) {
|
|
1340
|
+
this.agentMode = options.agent === true;
|
|
1341
|
+
this.operatorMode = options.operator === true;
|
|
1339
1342
|
const hasRuntimeToken = Boolean(process.env.VIGTHORIA_TOKEN || process.env.VIGTHORIA_AUTH_TOKEN);
|
|
1340
|
-
|
|
1343
|
+
const hasAgentServiceIdentity = this.agentMode && hasLocalV3ServiceIdentity();
|
|
1344
|
+
if (!this.config.isAuthenticated() && !hasRuntimeToken && !hasAgentServiceIdentity) {
|
|
1341
1345
|
throw new CliCommandError('Not authenticated. Run: vigthoria login', {
|
|
1342
1346
|
code: 'AUTH_REQUIRED', category: 'authentication',
|
|
1343
1347
|
});
|
|
1344
1348
|
}
|
|
1345
|
-
this.agentMode = options.agent === true;
|
|
1346
|
-
this.operatorMode = options.operator === true;
|
|
1347
1349
|
this.workflowTarget = typeof options.workflow === 'string' && options.workflow.trim()
|
|
1348
1350
|
? options.workflow.trim()
|
|
1349
1351
|
: null;
|
|
@@ -1884,26 +1886,14 @@ export class ChatCommand {
|
|
|
1884
1886
|
await this.runOperatorDirectAnswer(prompt);
|
|
1885
1887
|
return;
|
|
1886
1888
|
}
|
|
1887
|
-
// ── Repo-grounded operator path: try V3 agent first, then fall back ──
|
|
1888
|
-
// Prompts that reference files, code symbols, or analysis verbs need
|
|
1889
|
-
// tool access to read actual file contents. Route these through the
|
|
1890
|
-
// V3 agent (which archives runs for history/replay/fork and supports
|
|
1891
|
-
// workspace hydration) first. Falls back to local agent loop if V3
|
|
1892
|
-
// is unreachable.
|
|
1893
|
-
if (this.isRepoGroundedPrompt(prompt) && this.tools) {
|
|
1894
|
-
this.operatorMode = true;
|
|
1895
|
-
const handledByV3 = await this.tryV3AgentWorkflow(prompt);
|
|
1896
|
-
if (handledByV3) {
|
|
1897
|
-
this.saveSession();
|
|
1898
|
-
return;
|
|
1899
|
-
}
|
|
1900
|
-
await this.runLocalAgentLoop(prompt);
|
|
1901
|
-
return;
|
|
1902
|
-
}
|
|
1903
1889
|
getBridgeClient()?.emitPrompt({ prompt, mode: 'operator', model: this.currentModel });
|
|
1904
1890
|
const runtimeContext = await this.getPromptRuntimeContext(prompt);
|
|
1905
1891
|
const spinner = this.jsonOutput ? null : createSpinner({ text: 'Thinking like an operator...', spinner: 'clock' }).start();
|
|
1906
|
-
|
|
1892
|
+
// Operator is the BMAD surface. Keep grounded repository analysis on the
|
|
1893
|
+
// Operator service and make mutation intent explicit instead of silently
|
|
1894
|
+
// diverting it into V3 Agent mode. Read-only is the fail-safe default.
|
|
1895
|
+
const operatorTaskType = inferAgentTaskTypeWithContext(prompt);
|
|
1896
|
+
const workflowType = resolveWorkflowType(operatorTaskType, prompt);
|
|
1907
1897
|
const executionPrompt = this.buildExecutionPrompt(prompt);
|
|
1908
1898
|
try {
|
|
1909
1899
|
this.rememberBrainEvent('task', `GoA operator workflow started for prompt: ${prompt.slice(0, 220)}`, 'operator');
|
|
@@ -2963,6 +2953,10 @@ export class ChatCommand {
|
|
|
2963
2953
|
return false;
|
|
2964
2954
|
}
|
|
2965
2955
|
const errorMessage = `V3 agent workflow returned an incomplete result and legacy fallback is disabled. ${previewGate?.error || 'Workspace changes were not fully validated.'}`;
|
|
2956
|
+
const partialMutation = resolveAgentPartialMutation(changedFileCount, response.metadata?.partialMutation);
|
|
2957
|
+
liveOutcome.executorError = previewGate?.error || 'Template Service preview proof did not pass.';
|
|
2958
|
+
liveOutcome.failedTaskIds.add('preview-gate');
|
|
2959
|
+
liveOutcome.unfinishedTaskIds.delete('agent-run-in-progress');
|
|
2966
2960
|
if (spinner) {
|
|
2967
2961
|
spinner.stop();
|
|
2968
2962
|
}
|
|
@@ -2972,8 +2966,8 @@ export class ChatCommand {
|
|
|
2972
2966
|
watcher?.stop();
|
|
2973
2967
|
throw new CliCommandError(errorMessage, {
|
|
2974
2968
|
code: 'AGENT_PREVIEW_FAILED',
|
|
2975
|
-
category:
|
|
2976
|
-
partialMutation
|
|
2969
|
+
category: partialMutation === false ? 'execution' : 'partial_mutation',
|
|
2970
|
+
partialMutation,
|
|
2977
2971
|
details: { executionPath: 'v3-agent', previewGate },
|
|
2978
2972
|
});
|
|
2979
2973
|
}
|
|
@@ -3168,10 +3162,11 @@ export class ChatCommand {
|
|
|
3168
3162
|
}
|
|
3169
3163
|
}
|
|
3170
3164
|
if (!executorSucceeded) {
|
|
3165
|
+
const partialMutation = resolveAgentPartialMutation(changedFileCount, response.metadata?.partialMutation);
|
|
3171
3166
|
throw new CliCommandError(runEvaluation.statusHeadline, {
|
|
3172
3167
|
code: 'AGENT_INCOMPLETE',
|
|
3173
|
-
category:
|
|
3174
|
-
partialMutation
|
|
3168
|
+
category: partialMutation === false ? 'execution' : 'partial_mutation',
|
|
3169
|
+
partialMutation,
|
|
3175
3170
|
details: {
|
|
3176
3171
|
mode: 'agent',
|
|
3177
3172
|
model: routingPolicy.selectedModel,
|
|
@@ -3217,9 +3212,61 @@ export class ChatCommand {
|
|
|
3217
3212
|
catch (error) {
|
|
3218
3213
|
this.stopV3IdleWatch();
|
|
3219
3214
|
watcher?.stop();
|
|
3215
|
+
const persistTypedAgentFailure = (failure) => {
|
|
3216
|
+
const safeFailure = sanitizeUserFacingErrorText(failure.message || 'Agent execution failed.');
|
|
3217
|
+
liveOutcome.streamAborted = true;
|
|
3218
|
+
if (!liveOutcome.executorError)
|
|
3219
|
+
liveOutcome.executorError = safeFailure;
|
|
3220
|
+
if (failure.code === 'AGENT_PLAN_INVALID')
|
|
3221
|
+
liveOutcome.failedTaskIds.add('agent-plan');
|
|
3222
|
+
liveOutcome.unfinishedTaskIds.delete('agent-run-in-progress');
|
|
3223
|
+
this.commitAgentRunOutcome({
|
|
3224
|
+
prompt,
|
|
3225
|
+
originalPrompt: null,
|
|
3226
|
+
taskId: null,
|
|
3227
|
+
contextId: executionId,
|
|
3228
|
+
tasksSucceeded: liveOutcome.tasksSucceeded,
|
|
3229
|
+
tasksTotal: liveOutcome.tasksTotal,
|
|
3230
|
+
failedTaskIds: [...liveOutcome.failedTaskIds],
|
|
3231
|
+
unfinishedTaskIds: [...liveOutcome.unfinishedTaskIds],
|
|
3232
|
+
qualityScore: liveOutcome.qualityScore,
|
|
3233
|
+
qualityMissing: liveOutcome.qualityMissing,
|
|
3234
|
+
qualityBlockers: liveOutcome.qualityBlockers,
|
|
3235
|
+
hasOutput: this.api.hasAgentWorkspaceOutput(workspaceContext),
|
|
3236
|
+
answerContent: null,
|
|
3237
|
+
selfHealStatus: 'failed',
|
|
3238
|
+
selfHealTool: null,
|
|
3239
|
+
plannerError: liveOutcome.plannerError ? sanitizeUserFacingErrorText(liveOutcome.plannerError) : null,
|
|
3240
|
+
executorError: liveOutcome.executorError,
|
|
3241
|
+
clientToolErrors: this.api.getClientToolErrors(),
|
|
3242
|
+
transportErrors: this.api.getLastChatTransportErrors(),
|
|
3243
|
+
workspacePath: workspacePath || null,
|
|
3244
|
+
workspaceSyncIssue: null,
|
|
3245
|
+
finishedAt: Date.now(),
|
|
3246
|
+
}, prompt);
|
|
3247
|
+
this.updateAgentExecutionCheckpoint({
|
|
3248
|
+
status: 'failed',
|
|
3249
|
+
contextId: executionId,
|
|
3250
|
+
failedTaskIds: [...liveOutcome.failedTaskIds],
|
|
3251
|
+
unfinishedTaskIds: [...liveOutcome.unfinishedTaskIds],
|
|
3252
|
+
error: liveOutcome.executorError,
|
|
3253
|
+
});
|
|
3254
|
+
};
|
|
3255
|
+
if (error?.code === 'AGENT_PLAN_INVALID') {
|
|
3256
|
+
const planFailure = new CliCommandError(error.message, {
|
|
3257
|
+
code: 'AGENT_PLAN_INVALID',
|
|
3258
|
+
category: 'execution',
|
|
3259
|
+
partialMutation: error?.partialMutation ?? false,
|
|
3260
|
+
details: error?.mutation ? { mutation: error.mutation } : undefined,
|
|
3261
|
+
cause: error,
|
|
3262
|
+
});
|
|
3263
|
+
persistTypedAgentFailure(planFailure);
|
|
3264
|
+
throw planFailure;
|
|
3265
|
+
}
|
|
3220
3266
|
if (error instanceof CliCommandError) {
|
|
3221
3267
|
if (spinner)
|
|
3222
3268
|
spinner.stop();
|
|
3269
|
+
persistTypedAgentFailure(error);
|
|
3223
3270
|
throw error;
|
|
3224
3271
|
}
|
|
3225
3272
|
if (!this.api.hasAgentWorkspaceOutput(workspaceContext)) {
|
package/dist/commands/config.js
CHANGED
|
@@ -101,8 +101,8 @@ export class ConfigCommand {
|
|
|
101
101
|
message: 'Default AI model:',
|
|
102
102
|
choices: [
|
|
103
103
|
{ name: '═══ Code Models ═══', disabled: true },
|
|
104
|
-
{ name: 'Vigthoria v4 Creative 27B -
|
|
105
|
-
{ name: 'Vigthoria v4 Code 27B - Production executor', value: 'code' },
|
|
104
|
+
{ name: 'Vigthoria v4.2 Creative 27B - Multimodal architect and planning', value: 'architect' },
|
|
105
|
+
{ name: 'Vigthoria v4.2 Code 27B - Production executor', value: 'code' },
|
|
106
106
|
{ name: 'Vigthoria v4 Assistant 9B - Fast FIM and diagnostics', value: 'assistant' },
|
|
107
107
|
],
|
|
108
108
|
default: 'code',
|
|
@@ -309,8 +309,8 @@ export class ConfigCommand {
|
|
|
309
309
|
name: 'defaultModel',
|
|
310
310
|
message: 'Default AI model:',
|
|
311
311
|
choices: [
|
|
312
|
-
{ name: 'Vigthoria v4 Creative 27B — Architect', value: 'architect' },
|
|
313
|
-
{ name: 'Vigthoria v4 Code 27B — Executor', value: 'code' },
|
|
312
|
+
{ name: 'Vigthoria v4.2 Creative 27B — Multimodal Architect', value: 'architect' },
|
|
313
|
+
{ name: 'Vigthoria v4.2 Code 27B — Executor', value: 'code' },
|
|
314
314
|
{ name: 'Vigthoria v4 Assistant 9B — FIM and diagnostics', value: 'assistant' },
|
|
315
315
|
],
|
|
316
316
|
default: current.preferences.defaultModel,
|
package/dist/commands/fork.d.ts
CHANGED
|
@@ -7,10 +7,11 @@ interface ForkOptions {
|
|
|
7
7
|
}
|
|
8
8
|
export declare class ForkCommand {
|
|
9
9
|
private config;
|
|
10
|
-
|
|
10
|
+
private logger;
|
|
11
|
+
constructor(config: Config, logger: Logger);
|
|
11
12
|
private getHeaders;
|
|
12
13
|
private getBaseUrl;
|
|
13
|
-
private
|
|
14
|
+
private buildForkHistory;
|
|
14
15
|
run(runId: string, message: string, options: ForkOptions): Promise<void>;
|
|
15
16
|
}
|
|
16
17
|
export {};
|
package/dist/commands/fork.js
CHANGED
|
@@ -3,14 +3,17 @@ import { hasLocalV3AgentCapability } from '../utils/runtime-capability.js';
|
|
|
3
3
|
* fork.ts — Fork from an existing V3 agent run and stream the result.
|
|
4
4
|
*/
|
|
5
5
|
import chalk from 'chalk';
|
|
6
|
-
import { createRequire } from 'node:module';
|
|
7
6
|
import { createSpinner, CH } from '../utils/logger.js';
|
|
8
7
|
import { CliCommandError, commandFailure, formatSuccessJson } from '../utils/command-contract.js';
|
|
9
|
-
|
|
8
|
+
import { createAPIClient } from '../utils/api-client-factory.js';
|
|
9
|
+
import { buildLocalWorkspaceReference } from '../utils/workspace-reference.js';
|
|
10
|
+
import { guardedFetch } from '../utils/network-policy.js';
|
|
10
11
|
export class ForkCommand {
|
|
11
12
|
config;
|
|
12
|
-
|
|
13
|
+
logger;
|
|
14
|
+
constructor(config, logger) {
|
|
13
15
|
this.config = config;
|
|
16
|
+
this.logger = logger;
|
|
14
17
|
}
|
|
15
18
|
getHeaders() {
|
|
16
19
|
const headers = { 'Content-Type': 'application/json' };
|
|
@@ -34,50 +37,69 @@ export class ForkCommand {
|
|
|
34
37
|
(allowLocal ? 'http://127.0.0.1:8030' : null) ||
|
|
35
38
|
configuredApiUrl);
|
|
36
39
|
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
40
|
+
buildForkHistory(events, eventIndex) {
|
|
41
|
+
const selected = eventIndex > 0 ? events.slice(0, eventIndex) : events;
|
|
42
|
+
const lines = [
|
|
43
|
+
`Fork point: ${eventIndex > 0 ? eventIndex : events.length} of ${events.length} recorded events.`,
|
|
44
|
+
'Prior run evidence (metadata only; re-read current files through client tools):',
|
|
45
|
+
];
|
|
46
|
+
let toolCalls = 0;
|
|
47
|
+
for (const event of selected.slice(-120)) {
|
|
48
|
+
const type = String(event?.type || 'unknown');
|
|
49
|
+
if (type === 'plan') {
|
|
50
|
+
const count = Array.isArray(event.tasks) ? event.tasks.length : 0;
|
|
51
|
+
lines.push(`- plan: ${count} task(s)`);
|
|
45
52
|
}
|
|
46
|
-
|
|
53
|
+
else if (type === 'tool_call') {
|
|
54
|
+
toolCalls += 1;
|
|
55
|
+
lines.push(`- tool_call ${toolCalls}: ${String(event.name || 'unknown').slice(0, 80)}`);
|
|
56
|
+
}
|
|
57
|
+
else if (type === 'tool_result') {
|
|
58
|
+
lines.push(`- tool_result: ${String(event.name || 'unknown').slice(0, 80)} success=${event.success !== false}`);
|
|
59
|
+
}
|
|
60
|
+
else if (type === 'file_mutation') {
|
|
61
|
+
lines.push(`- file_mutation: ${String(event.kind || 'change').slice(0, 32)} (path intentionally omitted)`);
|
|
62
|
+
}
|
|
63
|
+
else if (type === 'complete') {
|
|
64
|
+
lines.push('- prior run reached its completion event');
|
|
65
|
+
}
|
|
66
|
+
else if (type === 'error') {
|
|
67
|
+
lines.push(`- prior run error code: ${String(event.code || event.error_code || 'unspecified').slice(0, 80)}`);
|
|
68
|
+
}
|
|
69
|
+
if (lines.join('\n').length > 12_000)
|
|
70
|
+
break;
|
|
47
71
|
}
|
|
48
|
-
return
|
|
72
|
+
return lines.join('\n').slice(0, 12_000);
|
|
49
73
|
}
|
|
50
74
|
async run(runId, message, options) {
|
|
51
75
|
const project = options.project || process.cwd();
|
|
52
|
-
const
|
|
76
|
+
const workspaceRef = buildLocalWorkspaceReference(project, String(this.config.get('userId') || this.config.get('email') || ''));
|
|
53
77
|
const eventIndex = options.eventIndex || 0;
|
|
54
|
-
const spinner = createSpinner(`
|
|
78
|
+
const spinner = createSpinner(`Loading run ${runId} for a local fork...`).start();
|
|
55
79
|
const streamController = new AbortController();
|
|
80
|
+
let api = null;
|
|
56
81
|
let interrupted = false;
|
|
57
82
|
const onInterrupt = () => {
|
|
58
83
|
interrupted = true;
|
|
59
84
|
streamController.abort();
|
|
85
|
+
api?.destroy();
|
|
60
86
|
};
|
|
61
87
|
process.once('SIGINT', onInterrupt);
|
|
62
88
|
try {
|
|
63
89
|
const baseUrl = this.getBaseUrl();
|
|
64
|
-
const
|
|
65
|
-
workspace_root:
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
};
|
|
71
|
-
const resp = await fetch(`${baseUrl}/api/runs/${encodeURIComponent(runId)}/fork`, {
|
|
72
|
-
method: 'POST',
|
|
90
|
+
const params = new URLSearchParams({
|
|
91
|
+
workspace_root: '',
|
|
92
|
+
local_workspace_path: workspaceRef,
|
|
93
|
+
project_path: workspaceRef,
|
|
94
|
+
});
|
|
95
|
+
const resp = await guardedFetch(`${baseUrl}/api/runs/${encodeURIComponent(runId)}/events?${params}`, {
|
|
73
96
|
headers: this.getHeaders(),
|
|
74
|
-
body: JSON.stringify(body),
|
|
75
97
|
signal: streamController.signal,
|
|
76
|
-
});
|
|
98
|
+
}, { audience: 'v3' });
|
|
77
99
|
if (!resp.ok) {
|
|
78
100
|
spinner.stop();
|
|
79
101
|
if (resp.status === 404) {
|
|
80
|
-
throw new CliCommandError(`Run ${runId} not found or has no event log.`, {
|
|
102
|
+
throw new CliCommandError(`Run ${runId} was not found or has no event log.`, {
|
|
81
103
|
code: 'RUN_NOT_FOUND', status: resp.status,
|
|
82
104
|
});
|
|
83
105
|
}
|
|
@@ -87,116 +109,94 @@ export class ForkCommand {
|
|
|
87
109
|
});
|
|
88
110
|
}
|
|
89
111
|
else {
|
|
90
|
-
throw new CliCommandError(`
|
|
112
|
+
throw new CliCommandError(`Could not load the fork source: ${resp.status} ${resp.statusText}`, {
|
|
91
113
|
code: 'RUN_FORK_FAILED', status: resp.status,
|
|
92
114
|
});
|
|
93
115
|
}
|
|
94
116
|
}
|
|
117
|
+
const source = (await resp.json());
|
|
118
|
+
const sourceEvents = Array.isArray(source.events) ? source.events : [];
|
|
119
|
+
if (eventIndex < 0 || eventIndex > sourceEvents.length) {
|
|
120
|
+
throw new CliCommandError(`Fork event index ${eventIndex} is outside 0..${sourceEvents.length}.`, {
|
|
121
|
+
code: 'RUN_FORK_EVENT_INDEX_INVALID',
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
const forkHistory = this.buildForkHistory(sourceEvents, eventIndex);
|
|
95
125
|
spinner.stop();
|
|
96
|
-
if (!options.json)
|
|
97
|
-
console.log(chalk.bold(`\n${CH.success}
|
|
98
|
-
if (!resp.body) {
|
|
99
|
-
throw new CliCommandError('Fork response did not contain an event stream', { code: 'RUN_FORK_STREAM_MISSING' });
|
|
126
|
+
if (!options.json) {
|
|
127
|
+
console.log(chalk.bold(`\n${CH.success} Starting local fork from ${chalk.cyan(runId)} at event ${eventIndex || sourceEvents.length}\n`));
|
|
100
128
|
}
|
|
101
|
-
|
|
102
|
-
const reader = resp.body.getReader();
|
|
103
|
-
const decoder = new TextDecoder();
|
|
104
|
-
let buffer = '';
|
|
129
|
+
const streamEvents = [];
|
|
105
130
|
let toolCallNum = 0;
|
|
106
|
-
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
131
|
+
api = createAPIClient(this.config, this.logger);
|
|
132
|
+
const request = [
|
|
133
|
+
message.trim() || 'Continue the previous run from the selected fork point.',
|
|
134
|
+
'',
|
|
135
|
+
forkHistory,
|
|
136
|
+
'',
|
|
137
|
+
'Use the current client-authoritative workspace as truth. Re-read every needed file through client tools; do not assume prior file contents.',
|
|
138
|
+
].join('\n');
|
|
139
|
+
const result = await api.runV3AgentWorkflow(request, {
|
|
140
|
+
projectPath: project,
|
|
141
|
+
targetPath: project,
|
|
142
|
+
workspacePath: project,
|
|
143
|
+
localWorkspacePath: project,
|
|
144
|
+
localMachineCapable: true,
|
|
145
|
+
clientToolExecution: true,
|
|
146
|
+
executionSurface: 'fork',
|
|
147
|
+
clientSurface: 'cli',
|
|
148
|
+
rawPrompt: message || request,
|
|
149
|
+
contextualPrompt: forkHistory,
|
|
150
|
+
forkedFrom: runId,
|
|
151
|
+
forkEventIndex: eventIndex,
|
|
152
|
+
onStreamEvent: (event) => {
|
|
153
|
+
streamEvents.push({
|
|
154
|
+
type: String(event.type || 'unknown'),
|
|
155
|
+
name: typeof event.name === 'string' ? event.name : undefined,
|
|
156
|
+
success: typeof event.success === 'boolean' ? event.success : undefined,
|
|
157
|
+
code: typeof event.code === 'string' ? event.code : undefined,
|
|
158
|
+
});
|
|
159
|
+
if (options.json)
|
|
160
|
+
return;
|
|
161
|
+
const type = String(event.type || 'unknown');
|
|
162
|
+
if (type === 'plan') {
|
|
163
|
+
console.log(chalk.magenta(` 📋 PLAN`) + ` ${event.tasks?.length || 0} tasks`);
|
|
138
164
|
}
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
events.push(evt);
|
|
143
|
-
if (options.json) {
|
|
144
|
-
continue;
|
|
145
|
-
}
|
|
146
|
-
switch (type) {
|
|
147
|
-
case 'context':
|
|
148
|
-
console.log(chalk.blue(` context: ${evt.context_id || '?'}`) +
|
|
149
|
-
(evt.forked_from ? chalk.dim(` (forked from ${evt.forked_from})`) : ''));
|
|
150
|
-
break;
|
|
151
|
-
case 'start':
|
|
152
|
-
console.log(chalk.green(` ▶ START`) + ` task=${evt.task_id || '?'}` +
|
|
153
|
-
(evt.forked_from ? chalk.dim(` forked_from=${evt.forked_from}`) : ''));
|
|
154
|
-
break;
|
|
155
|
-
case 'plan':
|
|
156
|
-
console.log(chalk.magenta(` 📋 PLAN`) + ` ${evt.tasks?.length || 0} tasks`);
|
|
157
|
-
break;
|
|
158
|
-
case 'tool_call':
|
|
159
|
-
toolCallNum++;
|
|
160
|
-
console.log(chalk.yellow(` 🔧 #${toolCallNum}`) + ` ${evt.name || '?'}(${JSON.stringify(evt.arguments || {}).substring(0, 60)})`);
|
|
161
|
-
break;
|
|
162
|
-
case 'tool_result': {
|
|
163
|
-
const icon = evt.success !== false ? chalk.green('✓') : chalk.red('✗');
|
|
164
|
-
console.log(` ${icon} ${evt.name || '?'}: ${chalk.dim((evt.output || '').substring(0, 100))}`);
|
|
165
|
-
break;
|
|
166
|
-
}
|
|
167
|
-
case 'message':
|
|
168
|
-
console.log(chalk.cyan(` 💬 `) + (evt.content || '').substring(0, 150));
|
|
169
|
-
break;
|
|
170
|
-
case 'complete': {
|
|
171
|
-
const seal = evt.seal_score ? `[${evt.seal_score.tier} ${evt.seal_score.overall}]` : '';
|
|
172
|
-
console.log(chalk.green(` ✅ COMPLETE `) + chalk.yellow(seal) +
|
|
173
|
-
` ${evt.iterations || '?'} iterations, ${evt.tool_calls || '?'} tool calls`);
|
|
174
|
-
break;
|
|
175
|
-
}
|
|
176
|
-
case 'error':
|
|
177
|
-
throw new CliCommandError(String(evt.message || 'Fork stream reported an error.'), {
|
|
178
|
-
code: 'RUN_FORK_STREAM_ERROR', details: evt,
|
|
179
|
-
});
|
|
180
|
-
default:
|
|
181
|
-
console.log(chalk.dim(` ${type}: ${JSON.stringify(evt).substring(0, 80)}`));
|
|
182
|
-
}
|
|
165
|
+
else if (type === 'tool_call') {
|
|
166
|
+
toolCallNum += 1;
|
|
167
|
+
console.log(chalk.yellow(` 🔧 #${toolCallNum}`) + ` ${event.name || '?'}`);
|
|
183
168
|
}
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
throw new CliCommandError('Fork event stream contained malformed JSON.', {
|
|
188
|
-
code: 'RUN_FORK_STREAM_MALFORMED', details: { payload: payload.slice(0, 200) }, cause: error,
|
|
189
|
-
});
|
|
169
|
+
else if (type === 'tool_result') {
|
|
170
|
+
const icon = event.success !== false ? chalk.green('✓') : chalk.red('✗');
|
|
171
|
+
console.log(` ${icon} ${event.name || '?'}`);
|
|
190
172
|
}
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
173
|
+
else if (type === 'message' && event.content) {
|
|
174
|
+
console.log(chalk.cyan(' 💬 ') + String(event.content).slice(0, 180));
|
|
175
|
+
}
|
|
176
|
+
else if (type === 'complete') {
|
|
177
|
+
console.log(chalk.green(' ✅ COMPLETE'));
|
|
178
|
+
}
|
|
179
|
+
},
|
|
180
|
+
});
|
|
181
|
+
if (result.partial) {
|
|
182
|
+
throw new CliCommandError('Fork execution ended with a partial result.', {
|
|
183
|
+
code: 'RUN_FORK_PARTIAL', details: { contextId: result.contextId, taskId: result.taskId },
|
|
184
|
+
});
|
|
195
185
|
}
|
|
196
186
|
if (options.json) {
|
|
197
|
-
console.log(formatSuccessJson('fork', {
|
|
187
|
+
console.log(formatSuccessJson('fork', {
|
|
188
|
+
runId,
|
|
189
|
+
eventIndex: eventIndex || sourceEvents.length,
|
|
190
|
+
taskId: result.taskId,
|
|
191
|
+
contextId: result.contextId,
|
|
192
|
+
content: result.content,
|
|
193
|
+
changedFiles: Object.keys(result.changedFiles || {}),
|
|
194
|
+
events: streamEvents,
|
|
195
|
+
}, { stream: true, eventCount: streamEvents.length, workspaceAuthority: 'client-tool-bridge' }));
|
|
198
196
|
}
|
|
199
197
|
else {
|
|
198
|
+
if (result.content)
|
|
199
|
+
console.log(result.content);
|
|
200
200
|
console.log(chalk.bold(`\n${CH.success} Fork run complete\n`));
|
|
201
201
|
}
|
|
202
202
|
}
|
|
@@ -208,6 +208,7 @@ export class ForkCommand {
|
|
|
208
208
|
throw commandFailure(err, { code: 'RUN_FORK_FAILED' });
|
|
209
209
|
}
|
|
210
210
|
finally {
|
|
211
|
+
api?.destroy();
|
|
211
212
|
process.removeListener('SIGINT', onInterrupt);
|
|
212
213
|
}
|
|
213
214
|
}
|
package/dist/commands/game.d.ts
CHANGED
|
@@ -8,6 +8,14 @@ export declare function gameProcessInvocation(pm: Manager, args: readonly string
|
|
|
8
8
|
executable: string;
|
|
9
9
|
args: string[];
|
|
10
10
|
};
|
|
11
|
+
export declare function windowsProcessTreeTerminationInvocation(pid: number, systemRoot?: string): {
|
|
12
|
+
executable: string;
|
|
13
|
+
args: string[];
|
|
14
|
+
};
|
|
15
|
+
export declare const runGameProcess: (pm: Manager, args: string[], cwd: string, timeoutMs?: number, outputMode?: "inherit" | "capture") => Promise<{
|
|
16
|
+
stdout: string;
|
|
17
|
+
stderr: string;
|
|
18
|
+
}>;
|
|
11
19
|
export declare class GameCommand {
|
|
12
20
|
private logger;
|
|
13
21
|
constructor(logger: Logger);
|