vigthoria-cli 1.10.0 → 1.10.36
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/auth.d.ts +1 -0
- package/dist/commands/auth.js +99 -17
- package/dist/commands/chat.d.ts +34 -0
- package/dist/commands/chat.js +1162 -61
- package/dist/commands/config.js +11 -2
- package/dist/commands/legion.js +8 -2
- package/dist/commands/wallet.d.ts +25 -0
- package/dist/commands/wallet.js +191 -0
- package/dist/index.js +158 -2
- package/dist/utils/api.d.ts +90 -2
- package/dist/utils/api.js +1730 -266
- package/dist/utils/config.d.ts +11 -0
- package/dist/utils/config.js +53 -12
- package/dist/utils/persona.d.ts +4 -0
- package/dist/utils/persona.js +34 -0
- package/dist/utils/tools.d.ts +5 -0
- package/dist/utils/tools.js +53 -1
- package/dist/utils/workspace-stream.js +56 -15
- package/install.ps1 +1 -1
- package/install.sh +1 -1
- package/package.json +4 -2
- package/scripts/release/validate-no-go-gates.sh +3 -1
package/dist/utils/config.d.ts
CHANGED
|
@@ -10,6 +10,7 @@ export interface VigthoriaCLIConfig {
|
|
|
10
10
|
refreshToken: string | null;
|
|
11
11
|
userId: string | null;
|
|
12
12
|
email: string | null;
|
|
13
|
+
v3ServiceKey: string | null;
|
|
13
14
|
subscription: {
|
|
14
15
|
plan: string | null;
|
|
15
16
|
status: string | null;
|
|
@@ -27,6 +28,14 @@ export interface VigthoriaCLIConfig {
|
|
|
27
28
|
rootPath: string | null;
|
|
28
29
|
ignorePatterns: string[];
|
|
29
30
|
};
|
|
31
|
+
persona: 'default' | 'wiener_grant';
|
|
32
|
+
hubModelPrefs?: {
|
|
33
|
+
enabledCloudModels: string[];
|
|
34
|
+
defaultCloudModel?: string;
|
|
35
|
+
defaultLocalModel?: string;
|
|
36
|
+
balance?: number;
|
|
37
|
+
fetchedAt?: string;
|
|
38
|
+
};
|
|
30
39
|
}
|
|
31
40
|
export interface AvailableModelDescriptor {
|
|
32
41
|
id: string;
|
|
@@ -68,7 +77,9 @@ export declare class Config {
|
|
|
68
77
|
expiresAt?: string;
|
|
69
78
|
}): void;
|
|
70
79
|
getAvailableModels(): AvailableModelDescriptor[];
|
|
80
|
+
refreshHubModelPreferences(): Promise<void>;
|
|
71
81
|
isCloudModel(modelId: string): boolean;
|
|
82
|
+
filterModelsByHubPreferences(models: AvailableModelDescriptor[], enabledCloudModels?: string[]): AvailableModelDescriptor[];
|
|
72
83
|
isComplexTask(prompt: string): boolean;
|
|
73
84
|
shouldUseCloudForHeavyTask(prompt: string): boolean;
|
|
74
85
|
}
|
package/dist/utils/config.js
CHANGED
|
@@ -12,6 +12,7 @@ const defaultConfig = {
|
|
|
12
12
|
refreshToken: null,
|
|
13
13
|
userId: null,
|
|
14
14
|
email: null,
|
|
15
|
+
v3ServiceKey: null,
|
|
15
16
|
subscription: {
|
|
16
17
|
plan: null,
|
|
17
18
|
status: null,
|
|
@@ -25,6 +26,7 @@ const defaultConfig = {
|
|
|
25
26
|
contextLines: 3,
|
|
26
27
|
maxTokens: 4096,
|
|
27
28
|
},
|
|
29
|
+
persona: 'default',
|
|
28
30
|
project: {
|
|
29
31
|
rootPath: null,
|
|
30
32
|
ignorePatterns: [
|
|
@@ -63,6 +65,7 @@ export class Config {
|
|
|
63
65
|
refreshToken: { type: ['string', 'null'] },
|
|
64
66
|
userId: { type: ['string', 'null'] },
|
|
65
67
|
email: { type: ['string', 'null'] },
|
|
68
|
+
v3ServiceKey: { type: ['string', 'null'] },
|
|
66
69
|
subscription: {
|
|
67
70
|
type: 'object',
|
|
68
71
|
properties: {
|
|
@@ -82,6 +85,7 @@ export class Config {
|
|
|
82
85
|
maxTokens: { type: 'number' },
|
|
83
86
|
},
|
|
84
87
|
},
|
|
88
|
+
persona: { type: 'string', enum: ['default', 'wiener_grant'] },
|
|
85
89
|
project: {
|
|
86
90
|
type: 'object',
|
|
87
91
|
properties: {
|
|
@@ -182,30 +186,64 @@ export class Config {
|
|
|
182
186
|
const sub = this.store.get('subscription');
|
|
183
187
|
const plan = (sub.plan || '').toLowerCase();
|
|
184
188
|
// ═══════════════════════════════════════════════════════════════
|
|
185
|
-
//
|
|
189
|
+
// Vigthoria server infrastructure operational models
|
|
186
190
|
// ═══════════════════════════════════════════════════════════════
|
|
187
191
|
const models = [
|
|
188
|
-
{ id: '
|
|
189
|
-
{ id: 'code', name: 'Vigthoria v3 Code 35B', description: 'Native 35B coding model on Blackwell', tier: 'local', backendModel: 'vigthoria-v3-code-35b' },
|
|
192
|
+
{ id: 'code', name: 'Vigthoria v3 Code 35B', description: 'Native 35B coding model on Blackwell (V3 pipeline)', tier: 'local', backendModel: 'vigthoria-v3-code-35b' },
|
|
190
193
|
{ id: 'code-35b', name: 'Vigthoria v3 Code 35B', description: 'Same flagship model as code', tier: 'local', backendModel: 'vigthoria-v3-code-35b' },
|
|
191
194
|
{ id: 'code-9b', name: 'Vigthoria v3 Code 9B', description: 'Efficient coding specialist for quick tasks', tier: 'local', backendModel: 'vigthoria-v3-code-9b' },
|
|
192
|
-
{ id: 'balanced', name: 'Vigthoria
|
|
193
|
-
{ id: 'balanced-4b', name: 'Vigthoria
|
|
195
|
+
{ id: 'balanced', name: 'Vigthoria Balanced 4B', description: 'Balanced general-purpose local model', tier: 'local', backendModel: 'vigthoria-v3-balanced-4b' },
|
|
196
|
+
{ id: 'balanced-4b', name: 'Vigthoria Balanced 4B', description: 'Efficient 4B general-purpose model (Qwen3.5-4B based)', tier: 'local', backendModel: 'vigthoria-v3-balanced-4b' },
|
|
194
197
|
];
|
|
195
|
-
// ═══════════════════════════════════════════════════════════════
|
|
196
|
-
// VIGTHORIA CLOUD - Premium cloud models (Pro subscription)
|
|
197
|
-
// For complex multi-file tasks, large refactoring, architecture
|
|
198
|
-
// ═══════════════════════════════════════════════════════════════
|
|
199
198
|
if (this.hasCloudAccess()) {
|
|
200
|
-
models.push({ id: 'cloud', name: 'Vigthoria Cloud
|
|
199
|
+
models.push({ id: 'cloud-fast', name: 'Vigthoria Cloud Fast', description: 'Fast cloud responses for lighter work', tier: 'cloud', backendModel: 'vigthoria-cloud-fast' }, { id: 'cloud-balanced', name: 'Vigthoria Cloud Balanced', description: 'Default quality/cost balance for chat and coding', tier: 'cloud', backendModel: 'vigthoria-cloud-balanced' }, { id: 'cloud-code', name: 'Vigthoria Cloud Code', description: 'Economical cloud coding and completion', tier: 'cloud', backendModel: 'vigthoria-cloud-code' }, { id: 'cloud-power', name: 'Vigthoria Cloud Power', description: 'Premium general intelligence for demanding work', tier: 'cloud', backendModel: 'vigthoria-cloud-power' }, { id: 'cloud-maximum', name: 'Vigthoria Cloud Maximum', description: 'Maximum power for complex architecture and reviews', tier: 'cloud', backendModel: 'vigthoria-cloud-maximum' },
|
|
200
|
+
// Legacy aliases
|
|
201
|
+
{ id: 'cloud', name: 'Vigthoria Cloud Balanced', description: 'Legacy alias for cloud-balanced', tier: 'cloud', backendModel: 'vigthoria-cloud-balanced' }, { id: 'cloud-reason', name: 'Vigthoria Cloud Balanced', description: 'Legacy alias for cloud-balanced', tier: 'cloud', backendModel: 'vigthoria-cloud-balanced' }, { id: 'ultra', name: 'Vigthoria Cloud Maximum', description: 'Legacy alias for cloud-maximum', tier: 'cloud', backendModel: 'vigthoria-cloud-maximum' });
|
|
202
|
+
}
|
|
203
|
+
const hubPrefs = this.store.get('hubModelPrefs');
|
|
204
|
+
if (hubPrefs?.enabledCloudModels?.length) {
|
|
205
|
+
return this.filterModelsByHubPreferences(models, hubPrefs.enabledCloudModels);
|
|
201
206
|
}
|
|
202
207
|
return models;
|
|
203
208
|
}
|
|
209
|
+
async refreshHubModelPreferences() {
|
|
210
|
+
const token = this.store.get('authToken');
|
|
211
|
+
const apiUrl = String(this.store.get('apiUrl') || '').replace(/\/$/, '');
|
|
212
|
+
if (!token || !apiUrl)
|
|
213
|
+
return;
|
|
214
|
+
try {
|
|
215
|
+
const response = await fetch(`${apiUrl}/api/user/credits/model-preferences`, {
|
|
216
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
217
|
+
signal: AbortSignal.timeout(8000),
|
|
218
|
+
});
|
|
219
|
+
if (!response.ok)
|
|
220
|
+
return;
|
|
221
|
+
const prefs = await response.json();
|
|
222
|
+
if (prefs?.success === false)
|
|
223
|
+
return;
|
|
224
|
+
this.store.set('hubModelPrefs', {
|
|
225
|
+
enabledCloudModels: Array.isArray(prefs.enabledCloudModels) ? prefs.enabledCloudModels : [],
|
|
226
|
+
defaultCloudModel: typeof prefs.defaultCloudModel === 'string' ? prefs.defaultCloudModel : undefined,
|
|
227
|
+
defaultLocalModel: typeof prefs.defaultLocalModel === 'string' ? prefs.defaultLocalModel : undefined,
|
|
228
|
+
balance: typeof prefs.balance === 'number' ? prefs.balance : undefined,
|
|
229
|
+
fetchedAt: new Date().toISOString(),
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
catch {
|
|
233
|
+
// Non-fatal: CLI can still run with default model catalog.
|
|
234
|
+
}
|
|
235
|
+
}
|
|
204
236
|
// Check if a model is a "Cloud" tier model
|
|
205
237
|
isCloudModel(modelId) {
|
|
206
|
-
const cloudModels = ['cloud', 'cloud-reason', 'ultra'];
|
|
238
|
+
const cloudModels = ['cloud-fast', 'cloud-balanced', 'cloud-code', 'cloud-power', 'cloud-maximum', 'cloud', 'cloud-reason', 'ultra'];
|
|
207
239
|
return cloudModels.includes(modelId) || modelId.includes('cloud');
|
|
208
240
|
}
|
|
241
|
+
filterModelsByHubPreferences(models, enabledCloudModels) {
|
|
242
|
+
if (!enabledCloudModels || !enabledCloudModels.length)
|
|
243
|
+
return models;
|
|
244
|
+
const enabled = new Set(enabledCloudModels);
|
|
245
|
+
return models.filter((model) => model.tier !== 'cloud' || enabled.has(model.backendModel));
|
|
246
|
+
}
|
|
209
247
|
// Check if task is complex enough to suggest Cloud upgrade
|
|
210
248
|
isComplexTask(prompt) {
|
|
211
249
|
const complexIndicators = [
|
|
@@ -221,6 +259,9 @@ export class Config {
|
|
|
221
259
|
return complexIndicators.some(pattern => pattern.test(prompt));
|
|
222
260
|
}
|
|
223
261
|
shouldUseCloudForHeavyTask(prompt) {
|
|
224
|
-
|
|
262
|
+
// DISABLED: Cloud routing is now EXPLICIT ONLY (--model cloud or /cloud command)
|
|
263
|
+
// Do NOT auto-route based on keywords. User must opt-in.
|
|
264
|
+
// If user wants cloud: they'll use --model cloud or request it explicitly.
|
|
265
|
+
return false;
|
|
225
266
|
}
|
|
226
267
|
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export type PersonaMode = 'default' | 'wiener_grant';
|
|
2
|
+
export declare function normalizePersonaMode(value: unknown): PersonaMode | null;
|
|
3
|
+
export declare function isToneDownPrompt(prompt: string): boolean;
|
|
4
|
+
export declare function buildPersonaOverlay(mode: PersonaMode, prompt?: string): string;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
const WIENER_GRANT_PROMPT = [
|
|
2
|
+
'Optional persona overlay: Wiener Grantler mode.',
|
|
3
|
+
'You remain Vigthoria: technically precise, helpful, safe, and comprehensive.',
|
|
4
|
+
'Persona: theatrical Viennese grumpiness with dry humor, mild sarcasm, impatient charm, and light Austrian dialect flavor.',
|
|
5
|
+
'Rules:',
|
|
6
|
+
'- Never reduce technical quality, completeness, or safety.',
|
|
7
|
+
'- Never use slurs, hate, racist or sexist stereotypes, protected-class insults, or demeaning nationality/ethnicity jokes.',
|
|
8
|
+
'- Do not seriously demean the user. Keep the bite playful and aimed at messy code, vague prompts, broken configs, or tooling chaos.',
|
|
9
|
+
'- Use dialect flavor sparingly enough that instructions, commands, and code remain fully readable.',
|
|
10
|
+
'- Always provide the actual fix, commands, code, or next steps.',
|
|
11
|
+
].join('\n');
|
|
12
|
+
const TONE_DOWN_PROMPT = [
|
|
13
|
+
'Tone-down rule active: this request appears safety-sensitive, destructive, auth/billing-related, security-related, legal/medical/financial, or production-critical.',
|
|
14
|
+
'Use only a very light flavor line if appropriate, then prioritize plain clarity, caution, and exact steps.',
|
|
15
|
+
].join('\n');
|
|
16
|
+
export function normalizePersonaMode(value) {
|
|
17
|
+
const normalized = String(value || '').trim().toLowerCase().replace(/_/g, '-');
|
|
18
|
+
if (!normalized || normalized === 'default' || normalized === 'off' || normalized === 'none')
|
|
19
|
+
return 'default';
|
|
20
|
+
if (normalized === 'wiener-grant' || normalized === 'wiener-grantler' || normalized === 'grant' || normalized === 'grantler')
|
|
21
|
+
return 'wiener_grant';
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
export function isToneDownPrompt(prompt) {
|
|
25
|
+
return /\b(delete|drop|destroy|wipe|rm\s+-rf|format|credential|secret|token|auth|login|billing|payment|wallet|security|vulnerability|exploit|incident|production|prod|deploy|legal|medical|financial|bank|tax)\b/i.test(prompt);
|
|
26
|
+
}
|
|
27
|
+
export function buildPersonaOverlay(mode, prompt = '') {
|
|
28
|
+
if (mode !== 'wiener_grant')
|
|
29
|
+
return '';
|
|
30
|
+
const parts = [WIENER_GRANT_PROMPT];
|
|
31
|
+
if (isToneDownPrompt(prompt))
|
|
32
|
+
parts.push(TONE_DOWN_PROMPT);
|
|
33
|
+
return parts.join('\n\n');
|
|
34
|
+
}
|
package/dist/utils/tools.d.ts
CHANGED
|
@@ -99,6 +99,9 @@ export declare class AgenticTools {
|
|
|
99
99
|
constructor(logger: Logger, cwd: string, permissionCallback: (action: string, options?: {
|
|
100
100
|
batchApproval?: boolean;
|
|
101
101
|
}) => Promise<boolean | 'batch' | 'persist'>, autoApprove?: boolean);
|
|
102
|
+
/** Rebind tool execution to a different local workspace root (e.g. prompt path override). */
|
|
103
|
+
setWorkspaceRoot(cwd: string): void;
|
|
104
|
+
getWorkspaceRoot(): string;
|
|
102
105
|
private getErrorMessage;
|
|
103
106
|
private assertToolCall;
|
|
104
107
|
/**
|
|
@@ -183,6 +186,8 @@ export declare class AgenticTools {
|
|
|
183
186
|
*/
|
|
184
187
|
private formatPermissionRequest;
|
|
185
188
|
private sleep;
|
|
189
|
+
private bridgeToolsEnabled;
|
|
190
|
+
private tryBridgeReadFile;
|
|
186
191
|
/**
|
|
187
192
|
* Read file with enhanced error handling and suggestions
|
|
188
193
|
*/
|
package/dist/utils/tools.js
CHANGED
|
@@ -449,10 +449,20 @@ export class AgenticTools {
|
|
|
449
449
|
throw new Error('AgenticTools initialization failed: autoApprove must be a boolean.');
|
|
450
450
|
}
|
|
451
451
|
this.logger = logger;
|
|
452
|
-
this.cwd = cwd;
|
|
452
|
+
this.cwd = path.resolve(cwd);
|
|
453
453
|
this.permissionCallback = permissionCallback;
|
|
454
454
|
this.autoApprove = autoApprove;
|
|
455
455
|
}
|
|
456
|
+
/** Rebind tool execution to a different local workspace root (e.g. prompt path override). */
|
|
457
|
+
setWorkspaceRoot(cwd) {
|
|
458
|
+
if (typeof cwd !== 'string' || cwd.trim().length === 0) {
|
|
459
|
+
throw new Error('AgenticTools.setWorkspaceRoot failed: cwd must be a non-empty string.');
|
|
460
|
+
}
|
|
461
|
+
this.cwd = path.resolve(cwd);
|
|
462
|
+
}
|
|
463
|
+
getWorkspaceRoot() {
|
|
464
|
+
return this.cwd;
|
|
465
|
+
}
|
|
456
466
|
getErrorMessage(error) {
|
|
457
467
|
if (error instanceof Error) {
|
|
458
468
|
return error.message;
|
|
@@ -1234,10 +1244,52 @@ export class AgenticTools {
|
|
|
1234
1244
|
return new Promise(resolve => setTimeout(resolve, ms));
|
|
1235
1245
|
}
|
|
1236
1246
|
// Tool implementations with enhanced error handling and undo support
|
|
1247
|
+
bridgeToolsEnabled() {
|
|
1248
|
+
const flag = String(process.env.VIGTHORIA_BRIDGE_TOOLS || '').trim().toLowerCase();
|
|
1249
|
+
return flag === '1' || flag === 'true' || flag === 'yes' || flag === 'on';
|
|
1250
|
+
}
|
|
1251
|
+
tryBridgeReadFile(args) {
|
|
1252
|
+
if (!this.bridgeToolsEnabled()) {
|
|
1253
|
+
return null;
|
|
1254
|
+
}
|
|
1255
|
+
const bridgeBase = String(process.env.VIGTHORIA_BRIDGE_HTTP
|
|
1256
|
+
|| process.env.VIGTHORIA_DESKTOP_BRIDGE_URL
|
|
1257
|
+
|| 'http://127.0.0.1:49160').replace(/\/$/, '');
|
|
1258
|
+
const targetPath = args.path || '';
|
|
1259
|
+
if (!targetPath) {
|
|
1260
|
+
return null;
|
|
1261
|
+
}
|
|
1262
|
+
try {
|
|
1263
|
+
const response = execSync(`curl -sS -m 15 -X POST "${bridgeBase}/tools/read_file" -H "Content-Type: application/json" -d ${JSON.stringify(JSON.stringify({
|
|
1264
|
+
path: targetPath,
|
|
1265
|
+
start_line: args.start_line ? Number(args.start_line) : undefined,
|
|
1266
|
+
end_line: args.end_line ? Number(args.end_line) : undefined,
|
|
1267
|
+
}))}`, { encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'] });
|
|
1268
|
+
const payload = JSON.parse(response);
|
|
1269
|
+
if (payload?.success === true) {
|
|
1270
|
+
return {
|
|
1271
|
+
success: true,
|
|
1272
|
+
output: String(payload.output || payload.content || ''),
|
|
1273
|
+
metadata: { source: 'desktop-bridge', path: targetPath },
|
|
1274
|
+
};
|
|
1275
|
+
}
|
|
1276
|
+
if (payload?.error) {
|
|
1277
|
+
this.logger.debug(`Desktop bridge read failed for ${targetPath}: ${payload.error}`);
|
|
1278
|
+
}
|
|
1279
|
+
}
|
|
1280
|
+
catch (error) {
|
|
1281
|
+
this.logger.debug(`Desktop bridge read unavailable for ${targetPath}: ${this.formatExternalToolError('read_file', 'bridge delegation', error)}`);
|
|
1282
|
+
}
|
|
1283
|
+
return null;
|
|
1284
|
+
}
|
|
1237
1285
|
/**
|
|
1238
1286
|
* Read file with enhanced error handling and suggestions
|
|
1239
1287
|
*/
|
|
1240
1288
|
readFile(args) {
|
|
1289
|
+
const bridgeRead = this.tryBridgeReadFile(args);
|
|
1290
|
+
if (bridgeRead) {
|
|
1291
|
+
return bridgeRead;
|
|
1292
|
+
}
|
|
1241
1293
|
const filePath = this.resolvePath(args.path);
|
|
1242
1294
|
if (!fs.existsSync(filePath)) {
|
|
1243
1295
|
// Try to find similar files
|
|
@@ -37,6 +37,17 @@ const IGNORE_PATTERNS = [
|
|
|
37
37
|
'**/.vigthoria/**',
|
|
38
38
|
'**/coverage/**',
|
|
39
39
|
'**/*.pyc',
|
|
40
|
+
// CRITICAL: Windows AppData & system directories (prevents EPERM errors)
|
|
41
|
+
'**/Anwendungsdaten/**', // German AppData
|
|
42
|
+
'**/AppData/**', // English AppData
|
|
43
|
+
'**/Local Settings/**', // Legacy Windows
|
|
44
|
+
'**/Application Data/**', // Legacy Windows
|
|
45
|
+
'**/$RECYCLE.BIN/**', // Windows Recycle Bin
|
|
46
|
+
'**/System Volume Information/**',
|
|
47
|
+
'**/Temp/**',
|
|
48
|
+
'**/tmp/**',
|
|
49
|
+
'**/OneDrive/**', // OneDrive cache
|
|
50
|
+
'**/MicrosoftEdgeBackups/**',
|
|
40
51
|
];
|
|
41
52
|
const BINARY_EXTENSIONS = new Set([
|
|
42
53
|
'.png', '.jpg', '.jpeg', '.gif', '.ico', '.svg', '.webp', '.bmp',
|
|
@@ -103,24 +114,54 @@ export class WorkspaceWatcher {
|
|
|
103
114
|
start() {
|
|
104
115
|
if (this.watcher)
|
|
105
116
|
return;
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
117
|
+
try {
|
|
118
|
+
this.watcher = chokidar.watch(this.workspaceRoot, {
|
|
119
|
+
ignored: IGNORE_PATTERNS,
|
|
120
|
+
persistent: false,
|
|
121
|
+
ignoreInitial: true,
|
|
122
|
+
awaitWriteFinish: { stabilityThreshold: 300, pollInterval: 100 },
|
|
123
|
+
// Windows-specific settings to prevent EPERM on system directories
|
|
124
|
+
usePolling: false,
|
|
125
|
+
interval: 100,
|
|
126
|
+
binaryInterval: 300,
|
|
127
|
+
depth: 50, // Limit traversal depth
|
|
128
|
+
});
|
|
129
|
+
this.watcher
|
|
130
|
+
.on('ready', () => {
|
|
131
|
+
this._ready = true;
|
|
132
|
+
logger.debug('Workspace watcher ready');
|
|
133
|
+
})
|
|
134
|
+
.on('add', (filePath) => this._handleChange(filePath, 'write'))
|
|
135
|
+
.on('change', (filePath) => this._handleChange(filePath, 'write'))
|
|
136
|
+
.on('unlink', (filePath) => this._handleChange(filePath, 'delete'))
|
|
137
|
+
// CRITICAL: Handle permission errors gracefully (Windows AppData EPERM)
|
|
138
|
+
.on('error', (error) => {
|
|
139
|
+
if (error?.code === 'EPERM' || error?.errno === -4048) {
|
|
140
|
+
logger.warn(`Workspace watcher permission error (ignored): ${error.message}`);
|
|
141
|
+
// Continue without watcher; don't crash
|
|
142
|
+
}
|
|
143
|
+
else {
|
|
144
|
+
logger.error(`Workspace watcher error: ${error?.message || error}`);
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
catch (err) {
|
|
149
|
+
// Handle initialization errors (e.g., EPERM during chokidar.watch setup)
|
|
150
|
+
if (err?.code === 'EPERM' || err?.errno === -4048 || err?.message?.includes('EPERM')) {
|
|
151
|
+
logger.warn(`Failed to initialize workspace watcher (EPERM): ${err.message}`);
|
|
152
|
+
logger.info('Continuing without file watcher; local file changes will not sync in real-time');
|
|
153
|
+
this.watcher = null;
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
logger.error(`Failed to initialize workspace watcher: ${err.message}`);
|
|
157
|
+
throw err;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
120
160
|
}
|
|
121
161
|
stop() {
|
|
122
162
|
if (this.watcher) {
|
|
123
|
-
|
|
163
|
+
// close() returns a Promise; fire-and-forget so handles are released
|
|
164
|
+
this.watcher.close().catch(() => { });
|
|
124
165
|
this.watcher = null;
|
|
125
166
|
this._ready = false;
|
|
126
167
|
}
|
package/install.ps1
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
$ErrorActionPreference = "Stop"
|
|
6
6
|
|
|
7
7
|
# Configuration
|
|
8
|
-
$CLI_VERSION = "1.
|
|
8
|
+
$CLI_VERSION = "1.10.18"
|
|
9
9
|
$INSTALL_DIR = "$env:USERPROFILE\.vigthoria"
|
|
10
10
|
$NPM_PACKAGE = "vigthoria-cli"
|
|
11
11
|
$GIT_PACKAGE_URL = "git+https://market.vigthoria.io/vigthoria/vigthoria-cli.git"
|
package/install.sh
CHANGED
|
@@ -26,7 +26,7 @@ else
|
|
|
26
26
|
fi
|
|
27
27
|
|
|
28
28
|
# Configuration
|
|
29
|
-
CLI_VERSION="1.
|
|
29
|
+
CLI_VERSION="1.10.18"
|
|
30
30
|
INSTALL_DIR="$HOME/.vigthoria"
|
|
31
31
|
REPO_URL="https://market.vigthoria.io/vigthoria/vigthoria-cli"
|
|
32
32
|
GIT_PACKAGE_URL="git+https://market.vigthoria.io/vigthoria/vigthoria-cli.git"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vigthoria-cli",
|
|
3
|
-
"version": "1.10.
|
|
3
|
+
"version": "1.10.36",
|
|
4
4
|
"description": "Vigthoria Coder CLI - AI-powered terminal coding assistant",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -65,7 +65,9 @@
|
|
|
65
65
|
"test:model:governance": "npm run build && node scripts/test-model-governance-no-agent.js",
|
|
66
66
|
"validate:no-go": "bash scripts/release/validate-no-go-gates.sh",
|
|
67
67
|
"test:legion:billing:e2e": "npm run build && node scripts/test-legion-godmode-billing-e2e.js",
|
|
68
|
-
"test:windows:v3-sync": "npm run build && node scripts/test-windows-v3-sync-recovery.js"
|
|
68
|
+
"test:windows:v3-sync": "npm run build && node scripts/test-windows-v3-sync-recovery.js",
|
|
69
|
+
"test:persona": "npm run build && node scripts/test-persona-mode.mjs",
|
|
70
|
+
"test:error-wording": "npm run build && node scripts/test-error-wording.mjs"
|
|
69
71
|
},
|
|
70
72
|
"keywords": [
|
|
71
73
|
"ai",
|
|
@@ -7,6 +7,8 @@ cd "$ROOT"
|
|
|
7
7
|
CLI="node dist/index.js"
|
|
8
8
|
unset V3_SERVICE_KEY
|
|
9
9
|
unset HYPERLOOP_SERVICE_KEY
|
|
10
|
+
# Release validation runs against local model-router in this environment
|
|
11
|
+
export VIGTHORIA_SELF_HOSTED_MODELS_API_URL="http://127.0.0.1:4009"
|
|
10
12
|
|
|
11
13
|
echo "[0.1-0.6] source/dist consistency"
|
|
12
14
|
node scripts/release/verify-runtime-consistency.mjs >/tmp/vig-verify-runtime.json
|
|
@@ -83,7 +85,7 @@ print('[pass] operator flow')
|
|
|
83
85
|
PY
|
|
84
86
|
|
|
85
87
|
echo "[7.1/7.3/7.4] local service health"
|
|
86
|
-
for u in http://localhost:8030/health http://localhost:
|
|
88
|
+
for u in http://localhost:8030/health http://localhost:4009/health http://localhost:4011/health; do
|
|
87
89
|
code=$(curl -s -o /dev/null -w "%{http_code}" "$u")
|
|
88
90
|
echo "$u => $code"
|
|
89
91
|
[[ "$code" == "200" ]]
|