vigthoria-cli 1.11.29 → 1.11.31
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 +39 -21
- package/dist/utils/agentRunOutcome.js +17 -0
- package/dist/utils/api.d.ts +1 -0
- package/dist/utils/api.js +74 -9
- package/dist/utils/v3-stream-events.d.ts +5 -0
- package/dist/utils/v3-stream-events.js +41 -0
- package/dist/utils/v3-workspace-path.js +47 -1
- package/package.json +3 -2
package/dist/commands/chat.js
CHANGED
|
@@ -20,6 +20,7 @@ import { emitDeckEvent, isDeckModeEnabled } from '../utils/deckEvents.js';
|
|
|
20
20
|
import { inferAgentTaskType as sharedInferAgentTaskType, inferAgentTaskTypeWithContext, isTrivialHtmlPageRequest, resolvePlannerAgentTimeoutMs, resolveWorkflowType, shouldSkipAnalysisRescue, taskRequiresWorkspaceChanges as promptRequiresWorkspaceChanges, taskRequiresWorkspaceChangesWithContext, buildExecutionHints, isAgentContinuePrompt, isAgentRetryPrompt, isBuiltContinuePrompt, isBuiltRetryPrompt, isBuiltWriteConfirmationPrompt, isConfirmationFollowUp, isWritePermissionGrant, } from '../utils/requestIntent.js';
|
|
21
21
|
import { resolveAgentRoute } from '../utils/agentRoute.js';
|
|
22
22
|
import { runTemplateInstantPath } from '../utils/templateInstantPath.js';
|
|
23
|
+
import { isV3StreamKeepaliveEvent } from '../utils/v3-stream-events.js';
|
|
23
24
|
const DEFAULT_V3_AGENT_TIMEOUT_MS = (() => {
|
|
24
25
|
const rawValue = process.env.VIGTHORIA_AGENT_TIMEOUT_MS || process.env.V3_AGENT_TIMEOUT_MS;
|
|
25
26
|
if (!rawValue) {
|
|
@@ -979,6 +980,9 @@ export class ChatCommand {
|
|
|
979
980
|
return;
|
|
980
981
|
}
|
|
981
982
|
this.v3LastActivity = Date.now();
|
|
983
|
+
if (isV3StreamKeepaliveEvent(event)) {
|
|
984
|
+
return;
|
|
985
|
+
}
|
|
982
986
|
if (event.type === 'tool_call') {
|
|
983
987
|
const eventKey = this.toolEventKey(event);
|
|
984
988
|
if (this.v3SeenToolCalls.has(eventKey)) {
|
|
@@ -1138,11 +1142,6 @@ export class ChatCommand {
|
|
|
1138
1142
|
const quality = this.sanitizeServerPath(plan.quality_profile || '');
|
|
1139
1143
|
const status = typeof plan.status === 'string' ? plan.status : '';
|
|
1140
1144
|
const summary = typeof plan.summary === 'string' ? this.sanitizeServerPath(plan.summary) : '';
|
|
1141
|
-
if (status === 'planning') {
|
|
1142
|
-
const elapsed = Number.isFinite(Number(plan.elapsed_seconds)) ? Number(plan.elapsed_seconds) : 0;
|
|
1143
|
-
spinner.text = elapsed > 0 ? `Planning... (${elapsed}s elapsed)` : 'Planning...';
|
|
1144
|
-
return;
|
|
1145
|
-
}
|
|
1146
1145
|
if (spinner.isSpinning)
|
|
1147
1146
|
spinner.stop();
|
|
1148
1147
|
process.stdout.write(chalk.cyan(` [Plan] `) + this.fitTerminalText(`Task: ${planKind || 'analyzing'}${quality ? ` (${quality})` : ''}`, 9) + '\n');
|
|
@@ -3003,6 +3002,21 @@ export class ChatCommand {
|
|
|
3003
3002
|
fastPath: this.lastAgentRoute?.fastPath,
|
|
3004
3003
|
priorPrompt: priorPrompt || null,
|
|
3005
3004
|
});
|
|
3005
|
+
const priorOutcome = this.lastAgentRunOutcome;
|
|
3006
|
+
const resumeTaskIds = priorOutcome
|
|
3007
|
+
? [...new Set([...(priorOutcome.failedTaskIds || []), ...(priorOutcome.unfinishedTaskIds || [])])]
|
|
3008
|
+
: [];
|
|
3009
|
+
const shouldResumePlan = isAgentContinuePrompt(contextualPrompt)
|
|
3010
|
+
|| isAgentRetryPrompt(contextualPrompt)
|
|
3011
|
+
|| isBuiltContinuePrompt(contextualPrompt)
|
|
3012
|
+
|| isBuiltRetryPrompt(contextualPrompt);
|
|
3013
|
+
const agentExecutionHints = shouldResumePlan
|
|
3014
|
+
? {
|
|
3015
|
+
...executionHints,
|
|
3016
|
+
resume_existing_plan: true,
|
|
3017
|
+
...(resumeTaskIds.length > 0 ? { remaining_task_ids: resumeTaskIds } : {}),
|
|
3018
|
+
}
|
|
3019
|
+
: executionHints;
|
|
3006
3020
|
const workspaceContext = {
|
|
3007
3021
|
workspacePath: workspacePath,
|
|
3008
3022
|
projectPath: workspacePath,
|
|
@@ -3039,7 +3053,7 @@ export class ChatCommand {
|
|
|
3039
3053
|
...workspaceContext,
|
|
3040
3054
|
agentTaskType,
|
|
3041
3055
|
workflowType,
|
|
3042
|
-
executionHints,
|
|
3056
|
+
executionHints: agentExecutionHints,
|
|
3043
3057
|
fastPath: this.lastAgentRoute?.fastPath,
|
|
3044
3058
|
agentRoute: this.lastAgentRoute,
|
|
3045
3059
|
executionSurface: 'cli',
|
|
@@ -3057,20 +3071,15 @@ export class ChatCommand {
|
|
|
3057
3071
|
history: this.getMessagesForModel(),
|
|
3058
3072
|
...runtimeContext,
|
|
3059
3073
|
onStreamEvent: (event) => {
|
|
3074
|
+
if (isV3StreamKeepaliveEvent(event)) {
|
|
3075
|
+
return;
|
|
3076
|
+
}
|
|
3060
3077
|
if (event.type === 'plan') {
|
|
3061
|
-
|
|
3062
|
-
const
|
|
3063
|
-
if (
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
}
|
|
3067
|
-
else {
|
|
3068
|
-
taskDisplay.complete(0);
|
|
3069
|
-
const tasks = plan?.tasks;
|
|
3070
|
-
if (Array.isArray(tasks) && tasks.length > 0) {
|
|
3071
|
-
taskDisplay.start(1);
|
|
3072
|
-
liveOutcome.tasksTotal = tasks.length;
|
|
3073
|
-
}
|
|
3078
|
+
taskDisplay.complete(0);
|
|
3079
|
+
const tasks = event?.plan?.tasks;
|
|
3080
|
+
if (Array.isArray(tasks) && tasks.length > 0) {
|
|
3081
|
+
taskDisplay.start(1);
|
|
3082
|
+
liveOutcome.tasksTotal = tasks.length;
|
|
3074
3083
|
}
|
|
3075
3084
|
}
|
|
3076
3085
|
else if (event.type === 'executor_start') {
|
|
@@ -3113,10 +3122,19 @@ export class ChatCommand {
|
|
|
3113
3122
|
}
|
|
3114
3123
|
else if (event.type === 'error') {
|
|
3115
3124
|
const msg = typeof event.message === 'string' ? event.message : '';
|
|
3116
|
-
|
|
3125
|
+
parsePlannerSummary(msg);
|
|
3126
|
+
const plannerSummary = /Planner-Executor completed/i.test(msg);
|
|
3127
|
+
const allTasksSucceeded = liveOutcome.tasksTotal > 0
|
|
3128
|
+
&& liveOutcome.tasksSucceeded >= liveOutcome.tasksTotal
|
|
3129
|
+
&& liveOutcome.failedTaskIds.size === 0;
|
|
3130
|
+
if (plannerSummary) {
|
|
3131
|
+
if (!allTasksSucceeded && !liveOutcome.plannerError) {
|
|
3132
|
+
liveOutcome.plannerError = msg;
|
|
3133
|
+
}
|
|
3134
|
+
}
|
|
3135
|
+
else if (/plan|planner|dependency graph/i.test(msg)) {
|
|
3117
3136
|
if (!liveOutcome.plannerError)
|
|
3118
3137
|
liveOutcome.plannerError = msg;
|
|
3119
|
-
parsePlannerSummary(msg);
|
|
3120
3138
|
}
|
|
3121
3139
|
else if (/executor|task failed|iteration/i.test(msg)) {
|
|
3122
3140
|
if (!liveOutcome.executorError)
|
|
@@ -206,6 +206,23 @@ export function evaluateExecutorSuccess(liveOutcome) {
|
|
|
206
206
|
const allTasksPassed = liveOutcome.tasksSucceeded === liveOutcome.tasksTotal;
|
|
207
207
|
const partialTasksPassed = liveOutcome.tasksSucceeded > 0;
|
|
208
208
|
const failedCount = liveOutcome.failedTaskIds.size;
|
|
209
|
+
if (allTasksPassed && failedCount === 0 && !liveOutcome.streamAborted) {
|
|
210
|
+
const qualityOnlyPlannerNote = Boolean(liveOutcome.plannerError)
|
|
211
|
+
&& /Planner-Executor completed:\s*\d+\s*\/\s*\d+\s+tasks succeeded/i.test(String(liveOutcome.plannerError));
|
|
212
|
+
const recoveredAfterTransientErrors = liveOutcome.executorFailed
|
|
213
|
+
|| Boolean(liveOutcome.executorError)
|
|
214
|
+
|| qualityOnlyPlannerNote;
|
|
215
|
+
if (!liveOutcome.plannerError || qualityOnlyPlannerNote || recoveredAfterTransientErrors) {
|
|
216
|
+
const qualityNote = qualityOnlyPlannerNote || /Quality (?:audit|blockers)/i.test(String(liveOutcome.plannerError || ''));
|
|
217
|
+
return {
|
|
218
|
+
executorSucceeded: true,
|
|
219
|
+
statusHeadline: qualityNote
|
|
220
|
+
? `✓ Tasks complete (${liveOutcome.tasksSucceeded}/${liveOutcome.tasksTotal}) — quality audit below target`
|
|
221
|
+
: `✓ Agent run finished (${liveOutcome.tasksSucceeded}/${liveOutcome.tasksTotal} tasks completed)`,
|
|
222
|
+
uiTheme: qualityNote ? 'warning' : 'success',
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
}
|
|
209
226
|
if (allTasksPassed && !hasFatalError) {
|
|
210
227
|
return {
|
|
211
228
|
executorSucceeded: true,
|
package/dist/utils/api.d.ts
CHANGED
|
@@ -272,6 +272,7 @@ export declare class APIClient {
|
|
|
272
272
|
*/
|
|
273
273
|
isAnalysisOnlyTask(message?: string, context?: Record<string, any>): boolean;
|
|
274
274
|
private normalizeWorkspaceRelativePath;
|
|
275
|
+
private collectAgentStateSyncPaths;
|
|
275
276
|
private listFrontendWorkspaceFiles;
|
|
276
277
|
private chooseFrontendPreviewEntry;
|
|
277
278
|
private extractLinkedFrontendAssets;
|
package/dist/utils/api.js
CHANGED
|
@@ -14,6 +14,7 @@ import { getChangedFiles } from './workspace-cache.js';
|
|
|
14
14
|
import { isSubstantiveAgentAnswer, isToolEvidenceStubAnswer } from './agentRunOutcome.js';
|
|
15
15
|
import { joinV3WorkspacePath, normalizeV3WorkspaceRelativePath } from './v3-workspace-path.js';
|
|
16
16
|
import { buildExecutionHints, isPlannerBuildTask, resolvePlannerAgentTimeoutMs } from './requestIntent.js';
|
|
17
|
+
import { isV3StreamKeepaliveEvent } from './v3-stream-events.js';
|
|
17
18
|
export const VIGTHORIA_HUB_CREDITS_URL = 'https://hub.vigthoria.io/credits';
|
|
18
19
|
export const VIGTHORIA_SERVER_TEMPORARILY_UNAVAILABLE_MESSAGE = 'Vigthoria Server is temporarily not available. Please try again later. If the issue persists, please contact support.';
|
|
19
20
|
export class CLIError extends Error {
|
|
@@ -732,6 +733,30 @@ export class APIClient {
|
|
|
732
733
|
normalizeWorkspaceRelativePath(filePath) {
|
|
733
734
|
return String(filePath || '').trim().replace(/\\/g, '/').replace(/^\.\//, '');
|
|
734
735
|
}
|
|
736
|
+
collectAgentStateSyncPaths(rootPath) {
|
|
737
|
+
const paths = [];
|
|
738
|
+
const progressPath = path.join(rootPath, '.vigthoria', 'agent-state', 'progress.json');
|
|
739
|
+
if (!fs.existsSync(progressPath)) {
|
|
740
|
+
return paths;
|
|
741
|
+
}
|
|
742
|
+
paths.push('.vigthoria/agent-state/progress.json');
|
|
743
|
+
const tasksDir = path.join(rootPath, '.vigthoria', 'agent-state', 'tasks');
|
|
744
|
+
if (!fs.existsSync(tasksDir)) {
|
|
745
|
+
return paths;
|
|
746
|
+
}
|
|
747
|
+
try {
|
|
748
|
+
for (const entry of fs.readdirSync(tasksDir, { withFileTypes: true })) {
|
|
749
|
+
if (!entry.isFile() || !entry.name.endsWith('.json')) {
|
|
750
|
+
continue;
|
|
751
|
+
}
|
|
752
|
+
paths.push(`.vigthoria/agent-state/tasks/${entry.name}`);
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
catch {
|
|
756
|
+
// Ignore unreadable task snapshots.
|
|
757
|
+
}
|
|
758
|
+
return paths;
|
|
759
|
+
}
|
|
735
760
|
listFrontendWorkspaceFiles(rootPath) {
|
|
736
761
|
const results = [];
|
|
737
762
|
const stack = [rootPath];
|
|
@@ -2401,7 +2426,8 @@ menu {
|
|
|
2401
2426
|
};
|
|
2402
2427
|
const snapshot = this.getAgentWorkspaceSnapshot(rootPath);
|
|
2403
2428
|
const candidatePaths = snapshot.paths.filter((entry) => !/(^|[\/\\])\.vigthoria([\/\\]|$)/.test(entry));
|
|
2404
|
-
|
|
2429
|
+
const agentStatePaths = this.collectAgentStateSyncPaths(rootPath);
|
|
2430
|
+
let orderedPaths = [...agentStatePaths, ...candidatePaths];
|
|
2405
2431
|
try {
|
|
2406
2432
|
const ranked = buildSemanticContext(rootPath, requestFocus, 60).topFiles.map((file) => file.path);
|
|
2407
2433
|
const changes = getChangedFiles(rootPath, candidatePaths);
|
|
@@ -2478,7 +2504,9 @@ menu {
|
|
|
2478
2504
|
continue;
|
|
2479
2505
|
if (/(^|[\/\\])\.(git|hg)([\/\\]|$)/.test(relativePath))
|
|
2480
2506
|
continue;
|
|
2481
|
-
|
|
2507
|
+
const normalizedPath = relativePath.replace(/\\/g, '/');
|
|
2508
|
+
const isAgentStateSync = /^\.vigthoria\/agent-state\//i.test(normalizedPath);
|
|
2509
|
+
if (!isAgentStateSync && /(^|[\/\\])\.vigthoria([\/\\]|$)/.test(relativePath))
|
|
2482
2510
|
continue;
|
|
2483
2511
|
const absolutePath = path.join(rootPath, relativePath);
|
|
2484
2512
|
try {
|
|
@@ -2646,6 +2674,18 @@ menu {
|
|
|
2646
2674
|
}
|
|
2647
2675
|
return;
|
|
2648
2676
|
}
|
|
2677
|
+
if (event.type === 'workspace_snapshot' && event.files && typeof event.files === 'object') {
|
|
2678
|
+
for (const [rawPath, content] of Object.entries(event.files)) {
|
|
2679
|
+
if (typeof content !== 'string') {
|
|
2680
|
+
continue;
|
|
2681
|
+
}
|
|
2682
|
+
const filePath = this.normalizeAgentWorkspaceRelativePath(rawPath, serverRoot || undefined);
|
|
2683
|
+
if (filePath) {
|
|
2684
|
+
streamedFiles[filePath] = content;
|
|
2685
|
+
}
|
|
2686
|
+
}
|
|
2687
|
+
return;
|
|
2688
|
+
}
|
|
2649
2689
|
// Only count confirmed mutations — not workspace snapshots (hydrated baseline)
|
|
2650
2690
|
// or tool_call previews that may still fail client-side / read-only guards.
|
|
2651
2691
|
if (event.type === 'tool_result' && event.success) {
|
|
@@ -2694,9 +2734,17 @@ menu {
|
|
|
2694
2734
|
}
|
|
2695
2735
|
return false;
|
|
2696
2736
|
}
|
|
2697
|
-
resolveV3ClientToolPath(rootPath, rawPath) {
|
|
2698
|
-
const
|
|
2699
|
-
|
|
2737
|
+
resolveV3ClientToolPath(rootPath, rawPath, sourceRoots = []) {
|
|
2738
|
+
const raw = String(rawPath || '.').trim();
|
|
2739
|
+
const roots = [rootPath, ...sourceRoots.filter(Boolean)];
|
|
2740
|
+
let relativePath = '';
|
|
2741
|
+
for (const sourceRoot of roots) {
|
|
2742
|
+
relativePath = this.normalizeAgentWorkspaceRelativePath(raw, sourceRoot);
|
|
2743
|
+
if (relativePath || raw === '.' || raw === '') {
|
|
2744
|
+
break;
|
|
2745
|
+
}
|
|
2746
|
+
}
|
|
2747
|
+
if (!relativePath && raw !== '.' && raw !== '') {
|
|
2700
2748
|
return null;
|
|
2701
2749
|
}
|
|
2702
2750
|
const absolutePath = relativePath ? joinV3WorkspacePath(rootPath, relativePath) : path.resolve(rootPath);
|
|
@@ -2747,7 +2795,8 @@ menu {
|
|
|
2747
2795
|
}
|
|
2748
2796
|
const name = String(event.name || event.tool || '').trim();
|
|
2749
2797
|
const args = event.arguments || {};
|
|
2750
|
-
const
|
|
2798
|
+
const serverRoot = String(context.__v3ServerWorkspaceRoot || '').trim();
|
|
2799
|
+
const target = this.resolveV3ClientToolPath(rootPath, args.path || args.cwd || '.', serverRoot ? [serverRoot] : []);
|
|
2751
2800
|
if (!target) {
|
|
2752
2801
|
return { success: false, output: '', error: 'Tool path is outside the workspace.' };
|
|
2753
2802
|
}
|
|
@@ -2831,6 +2880,14 @@ menu {
|
|
|
2831
2880
|
error: `File not found: ${target.relativePath}. Write the file before running syntax_check.`,
|
|
2832
2881
|
};
|
|
2833
2882
|
}
|
|
2883
|
+
const stat = fs.statSync(target.absolutePath);
|
|
2884
|
+
if (stat.isDirectory()) {
|
|
2885
|
+
return {
|
|
2886
|
+
success: false,
|
|
2887
|
+
output: '',
|
|
2888
|
+
error: `Expected a file, but path is a directory: ${target.relativePath}`,
|
|
2889
|
+
};
|
|
2890
|
+
}
|
|
2834
2891
|
const ext = path.extname(target.absolutePath).toLowerCase();
|
|
2835
2892
|
if (ext === '.json') {
|
|
2836
2893
|
JSON.parse(fs.readFileSync(target.absolutePath, 'utf8'));
|
|
@@ -2851,12 +2908,19 @@ menu {
|
|
|
2851
2908
|
return { success: true, output: `Syntax check passed: ${target.relativePath}` };
|
|
2852
2909
|
}
|
|
2853
2910
|
if (name === 'run_command') {
|
|
2854
|
-
|
|
2911
|
+
let command = String(args.command || '').trim();
|
|
2855
2912
|
if (!command)
|
|
2856
2913
|
return { success: false, output: '', error: 'run_command requires command.' };
|
|
2914
|
+
if (process.platform === 'win32' && /^ls(\s|$)/i.test(command)) {
|
|
2915
|
+
command = command.replace(/^ls\b/i, 'dir');
|
|
2916
|
+
}
|
|
2857
2917
|
const { exec } = await import('child_process');
|
|
2858
2918
|
return await new Promise((resolve) => {
|
|
2859
|
-
exec(command, {
|
|
2919
|
+
exec(command, {
|
|
2920
|
+
cwd: target.absolutePath,
|
|
2921
|
+
timeout: Number(args.timeout || 30000),
|
|
2922
|
+
shell: process.platform === 'win32' ? 'cmd.exe' : undefined,
|
|
2923
|
+
}, (error, stdout, stderr) => {
|
|
2860
2924
|
resolve({
|
|
2861
2925
|
success: !error,
|
|
2862
2926
|
output: String(stdout || stderr || '').slice(0, 12000),
|
|
@@ -3688,6 +3752,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
3688
3752
|
}
|
|
3689
3753
|
if (!serverWorkspaceRoot && event.type === 'context' && typeof event.workspace_root === 'string' && event.workspace_root.trim()) {
|
|
3690
3754
|
serverWorkspaceRoot = event.workspace_root.trim();
|
|
3755
|
+
context.__v3ServerWorkspaceRoot = serverWorkspaceRoot;
|
|
3691
3756
|
}
|
|
3692
3757
|
if (event.type === 'client_tool_request') {
|
|
3693
3758
|
const toolTask = this.handleV3ClientToolRequest(event, context, response.url).catch((error) => {
|
|
@@ -3721,7 +3786,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
3721
3786
|
}
|
|
3722
3787
|
}
|
|
3723
3788
|
}
|
|
3724
|
-
if (typeof context.onStreamEvent === 'function') {
|
|
3789
|
+
if (typeof context.onStreamEvent === 'function' && !isV3StreamKeepaliveEvent(userEvent)) {
|
|
3725
3790
|
try {
|
|
3726
3791
|
context.onStreamEvent(userEvent);
|
|
3727
3792
|
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Detect V3 agent SSE keepalive/heartbeat events that exist only to keep
|
|
3
|
+
* connections alive — not substantive work the CLI should surface as progress.
|
|
4
|
+
*/
|
|
5
|
+
const PLANNING_KEEPALIVE = /^Planning in progress\.\.\.\s*\(\d+s(?:\s+elapsed)?\)$/i;
|
|
6
|
+
const PARALLEL_KEEPALIVE = /^Parallel tasks in progress\.\.\.\s*\(\d+s(?:\s+elapsed)?\)$/i;
|
|
7
|
+
const GENERIC_ELAPSED_KEEPALIVE = /\bin progress\b.*\(\d+s(?:\s+elapsed)?\)$/i;
|
|
8
|
+
export function isV3StreamKeepaliveEvent(event) {
|
|
9
|
+
if (!event || typeof event !== 'object') {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
const record = event;
|
|
13
|
+
const type = typeof record.type === 'string' ? record.type : '';
|
|
14
|
+
if (type === 'heartbeat') {
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
17
|
+
if (type === 'progress' || type === 'status') {
|
|
18
|
+
const content = String(record.content || record.message || record.status || '').trim();
|
|
19
|
+
if (!content) {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
if (PLANNING_KEEPALIVE.test(content) || PARALLEL_KEEPALIVE.test(content)) {
|
|
23
|
+
return true;
|
|
24
|
+
}
|
|
25
|
+
if (GENERIC_ELAPSED_KEEPALIVE.test(content)) {
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
if (type === 'plan') {
|
|
30
|
+
const plan = record.plan;
|
|
31
|
+
if (plan && typeof plan === 'object') {
|
|
32
|
+
const planRecord = plan;
|
|
33
|
+
const status = typeof planRecord.status === 'string' ? planRecord.status : '';
|
|
34
|
+
const tasks = planRecord.tasks;
|
|
35
|
+
if (status === 'planning' && !Array.isArray(tasks)) {
|
|
36
|
+
return true;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
@@ -42,6 +42,36 @@ export function normalizeV3WorkspaceRelativePath(rawPath, rootPath) {
|
|
|
42
42
|
}
|
|
43
43
|
return null;
|
|
44
44
|
};
|
|
45
|
+
const stripScrubbedPlaceholder = (value) => {
|
|
46
|
+
const candidate = String(value || '').replace(/^\/+/, '');
|
|
47
|
+
const placeholderPatterns = [
|
|
48
|
+
[/^(?:var\/)?www\/\[internal\](?:\/(.*))?$/i, 1],
|
|
49
|
+
[/^\[internal\](?:\/(.*))?$/i, 1],
|
|
50
|
+
[/^\[Vigthoria service\](?:\/(.*))?$/i, 1],
|
|
51
|
+
[/^\[Vigthoria Agent\](?:\/(.*))?$/i, 1],
|
|
52
|
+
[/^\[Vigthoria storage\](?:\/(.*))?$/i, 1],
|
|
53
|
+
[/^\[temp\](?:\/(.*))?$/i, 1],
|
|
54
|
+
[/^\[home\](?:\/(.*))?$/i, 1],
|
|
55
|
+
[/^\[workspace\](?:\/(.*))?$/i, 1],
|
|
56
|
+
[/^(?:var\/)?www\/\[Vigthoria service\](?:\/(.*))?$/i, 1],
|
|
57
|
+
];
|
|
58
|
+
for (const [pattern, groupIndex] of placeholderPatterns) {
|
|
59
|
+
const match = candidate.match(pattern);
|
|
60
|
+
if (match) {
|
|
61
|
+
return safeRelative(match[groupIndex] || '');
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
const bracketSplit = candidate.split(/\[(?:internal|Vigthoria service|Vigthoria Agent|temp|home|workspace)\]/i);
|
|
65
|
+
if (bracketSplit.length > 1) {
|
|
66
|
+
const tail = bracketSplit[bracketSplit.length - 1].replace(/^\/+/, '');
|
|
67
|
+
return safeRelative(tail);
|
|
68
|
+
}
|
|
69
|
+
return null;
|
|
70
|
+
};
|
|
71
|
+
const scrubbed = stripScrubbedPlaceholder(input);
|
|
72
|
+
if (scrubbed !== null) {
|
|
73
|
+
return scrubbed;
|
|
74
|
+
}
|
|
45
75
|
const decoded = decodeBoundaryUri(input);
|
|
46
76
|
if (decoded !== null) {
|
|
47
77
|
return decoded;
|
|
@@ -72,6 +102,18 @@ export function normalizeV3WorkspaceRelativePath(rawPath, rootPath) {
|
|
|
72
102
|
}
|
|
73
103
|
const normalizedRoot = String(rootPath || '').trim().replace(/\\/g, '/').replace(/\/+$/g, '');
|
|
74
104
|
if (normalizedRoot) {
|
|
105
|
+
if (/^[a-zA-Z]:\//.test(input)) {
|
|
106
|
+
const winRoot = normalizedRoot;
|
|
107
|
+
const inputLower = input.toLowerCase();
|
|
108
|
+
const winRootLower = winRoot.toLowerCase();
|
|
109
|
+
if (inputLower === winRootLower || inputLower === `${winRootLower}/`) {
|
|
110
|
+
return '';
|
|
111
|
+
}
|
|
112
|
+
if (inputLower.startsWith(`${winRootLower}/`)) {
|
|
113
|
+
return safeRelative(input.slice(winRoot.length + 1));
|
|
114
|
+
}
|
|
115
|
+
return '';
|
|
116
|
+
}
|
|
75
117
|
const rootNoLeadingSlash = normalizedRoot.replace(/^\//, '');
|
|
76
118
|
const rootBase = path.posix.basename(normalizedRoot);
|
|
77
119
|
const prefixes = [
|
|
@@ -90,7 +132,11 @@ export function normalizeV3WorkspaceRelativePath(rawPath, rootPath) {
|
|
|
90
132
|
return safeRelative(input.slice(embeddedIndex + embeddedRoot.length));
|
|
91
133
|
}
|
|
92
134
|
}
|
|
93
|
-
|
|
135
|
+
const relative = safeRelative(input);
|
|
136
|
+
if (relative === 'workspace') {
|
|
137
|
+
return '';
|
|
138
|
+
}
|
|
139
|
+
return relative;
|
|
94
140
|
}
|
|
95
141
|
/** Join workspace root + relative path without path.resolve URI corruption on Windows. */
|
|
96
142
|
export function joinV3WorkspacePath(rootPath, relativePath) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vigthoria-cli",
|
|
3
|
-
"version": "1.11.
|
|
3
|
+
"version": "1.11.31",
|
|
4
4
|
"description": "Vigthoria Coder CLI - AI-powered terminal coding assistant",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -68,7 +68,8 @@
|
|
|
68
68
|
"test:model:governance": "npm run build && node scripts/test-model-governance-no-agent.js",
|
|
69
69
|
"validate:no-go": "bash scripts/release/validate-no-go-gates.sh",
|
|
70
70
|
"test:legion:billing:e2e": "npm run build && node scripts/test-legion-godmode-billing-e2e.js",
|
|
71
|
-
"test:windows:v3-sync": "npm run build && node scripts/test-windows-v3-sync-recovery.js"
|
|
71
|
+
"test:windows:v3-sync": "npm run build && node scripts/test-windows-v3-sync-recovery.js",
|
|
72
|
+
"test:v3-workspace-path": "npm run build && node scripts/test-v3-workspace-path.js"
|
|
72
73
|
},
|
|
73
74
|
"keywords": [
|
|
74
75
|
"ai",
|