vigthoria-cli 1.10.36 → 1.10.47

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.
Files changed (62) hide show
  1. package/dist/commands/agent-session-menu.d.ts +19 -0
  2. package/dist/commands/agent-session-menu.js +155 -0
  3. package/dist/commands/auth.js +68 -51
  4. package/dist/commands/bridge.js +19 -12
  5. package/dist/commands/cancel.js +22 -15
  6. package/dist/commands/chat.d.ts +0 -22
  7. package/dist/commands/chat.js +402 -1084
  8. package/dist/commands/config.js +73 -33
  9. package/dist/commands/deploy.js +123 -83
  10. package/dist/commands/device.js +61 -21
  11. package/dist/commands/edit.js +39 -32
  12. package/dist/commands/explain.js +25 -18
  13. package/dist/commands/generate.js +44 -37
  14. package/dist/commands/hub.js +102 -95
  15. package/dist/commands/index.js +46 -41
  16. package/dist/commands/legion.js +186 -146
  17. package/dist/commands/review.js +36 -29
  18. package/dist/commands/security.js +12 -5
  19. package/dist/commands/wallet.js +35 -28
  20. package/dist/commands/workflow.js +20 -13
  21. package/dist/utils/brain-hub-client.d.ts +32 -0
  22. package/dist/utils/brain-hub-client.js +52 -0
  23. package/dist/utils/bridge-client.js +52 -11
  24. package/dist/utils/codebase-indexer.d.ts +59 -0
  25. package/dist/utils/codebase-indexer.js +351 -0
  26. package/dist/utils/context-ranker.js +21 -15
  27. package/dist/utils/files.js +42 -5
  28. package/dist/utils/logger.js +50 -42
  29. package/dist/utils/persona.js +8 -3
  30. package/dist/utils/post-write-validator.js +29 -22
  31. package/dist/utils/project-memory.js +23 -16
  32. package/dist/utils/task-display.js +20 -13
  33. package/dist/utils/workspace-brain-service.d.ts +43 -0
  34. package/dist/utils/workspace-brain-service.js +158 -0
  35. package/dist/utils/workspace-cache.js +26 -18
  36. package/dist/utils/workspace-stream.js +63 -21
  37. package/package.json +3 -6
  38. package/scripts/release/validate-no-go-gates.sh +1 -1
  39. package/dist/commands/fork.d.ts +0 -17
  40. package/dist/commands/fork.js +0 -164
  41. package/dist/commands/history.d.ts +0 -17
  42. package/dist/commands/history.js +0 -113
  43. package/dist/commands/preview.d.ts +0 -55
  44. package/dist/commands/preview.js +0 -467
  45. package/dist/commands/replay.d.ts +0 -18
  46. package/dist/commands/replay.js +0 -156
  47. package/dist/commands/repo.d.ts +0 -97
  48. package/dist/commands/repo.js +0 -773
  49. package/dist/commands/update.d.ts +0 -9
  50. package/dist/commands/update.js +0 -201
  51. package/dist/index.d.ts +0 -21
  52. package/dist/index.js +0 -1823
  53. package/dist/utils/api.d.ts +0 -572
  54. package/dist/utils/api.js +0 -6548
  55. package/dist/utils/cli-state.d.ts +0 -54
  56. package/dist/utils/cli-state.js +0 -185
  57. package/dist/utils/config.d.ts +0 -85
  58. package/dist/utils/config.js +0 -267
  59. package/dist/utils/session.d.ts +0 -118
  60. package/dist/utils/session.js +0 -423
  61. package/dist/utils/tools.d.ts +0 -274
  62. package/dist/utils/tools.js +0 -3502
@@ -1,54 +0,0 @@
1
- /**
2
- * Vigthoria CLI — shared local-state helpers.
3
- *
4
- * Single source for:
5
- * • Offline-mode detection (VIGTHORIA_OFFLINE=1) — suppresses every
6
- * background network call (update checks, gateway preflights, etc.).
7
- * • Telemetry opt-out (VIGTHORIA_TELEMETRY_DISABLED=1).
8
- * • Update-check cache, so `npm view` is not invoked on every CLI start.
9
- * • Cross-platform safe file mode enforcement for tokens / sessions.
10
- *
11
- * No external network calls — pure local helpers. Safe to import from
12
- * any command module.
13
- */
14
- /** 24h is plenty for an update-check ping. */
15
- export declare const UPDATE_CHECK_TTL_MS: number;
16
- /** 60s gateway-preflight cache so back-to-back CLI invocations stay fast. */
17
- export declare const GATEWAY_PREFLIGHT_TTL_MS: number;
18
- export interface CliStateShape {
19
- updateCheck?: {
20
- checkedAt: number;
21
- latestVersion: string;
22
- notifiedFor?: string;
23
- };
24
- gatewayPreflight?: {
25
- checkedAt: number;
26
- valid: boolean;
27
- };
28
- /** Last-seen version — used to render release notes on upgrade. */
29
- lastSeenVersion?: string;
30
- }
31
- export declare function ensureStateDir(): void;
32
- /** Best-effort lock-down: `0o600` on POSIX, no-op on Windows (NTFS ACL ≠ chmod). */
33
- export declare function secureFileMode(filePath: string): void;
34
- /** Atomic write helper — write to temp then rename, never half-written JSON. */
35
- export declare function atomicWriteJson(targetPath: string, value: unknown, mode?: number): void;
36
- export declare function loadCliState(): CliStateShape;
37
- export declare function saveCliState(state: CliStateShape): void;
38
- export declare function getCliStateFile(): string;
39
- /**
40
- * Offline mode — set VIGTHORIA_OFFLINE=1 to skip every non-essential
41
- * outbound HTTP call. Useful for restricted networks, air-gapped runs,
42
- * and deterministic CI.
43
- */
44
- export declare function isOfflineMode(): boolean;
45
- /** Telemetry opt-out (also implied when offline mode is on). */
46
- export declare function isTelemetryDisabled(): boolean;
47
- /** When true the startup update check is suppressed (env override or offline). */
48
- export declare function isUpdateCheckSuppressed(): boolean;
49
- /** Cached read for the latest known version — null when stale or absent. */
50
- export declare function readCachedLatestVersion(maxAgeMs?: number): string | null;
51
- export declare function writeCachedLatestVersion(latestVersion: string, notifiedFor?: string): void;
52
- export declare function readGatewayPreflightCache(maxAgeMs?: number): boolean | null;
53
- export declare function writeGatewayPreflightCache(valid: boolean): void;
54
- export declare function isSafeNpmPackageSpec(spec: string): boolean;
@@ -1,185 +0,0 @@
1
- /**
2
- * Vigthoria CLI — shared local-state helpers.
3
- *
4
- * Single source for:
5
- * • Offline-mode detection (VIGTHORIA_OFFLINE=1) — suppresses every
6
- * background network call (update checks, gateway preflights, etc.).
7
- * • Telemetry opt-out (VIGTHORIA_TELEMETRY_DISABLED=1).
8
- * • Update-check cache, so `npm view` is not invoked on every CLI start.
9
- * • Cross-platform safe file mode enforcement for tokens / sessions.
10
- *
11
- * No external network calls — pure local helpers. Safe to import from
12
- * any command module.
13
- */
14
- import * as fs from 'fs';
15
- import * as os from 'os';
16
- import * as path from 'path';
17
- const STATE_DIR = path.join(os.homedir(), '.vigthoria');
18
- const STATE_FILE = path.join(STATE_DIR, 'cli-state.json');
19
- /** 24h is plenty for an update-check ping. */
20
- export const UPDATE_CHECK_TTL_MS = 24 * 60 * 60 * 1000;
21
- /** 60s gateway-preflight cache so back-to-back CLI invocations stay fast. */
22
- export const GATEWAY_PREFLIGHT_TTL_MS = 60 * 1000;
23
- function readStateUnchecked() {
24
- try {
25
- if (!fs.existsSync(STATE_FILE)) {
26
- return {};
27
- }
28
- const text = fs.readFileSync(STATE_FILE, 'utf8');
29
- if (!text.trim()) {
30
- return {};
31
- }
32
- const parsed = JSON.parse(text);
33
- return parsed && typeof parsed === 'object' ? parsed : {};
34
- }
35
- catch {
36
- // Corrupt state file should never crash the CLI — treat as empty.
37
- return {};
38
- }
39
- }
40
- export function ensureStateDir() {
41
- try {
42
- if (!fs.existsSync(STATE_DIR)) {
43
- fs.mkdirSync(STATE_DIR, { recursive: true, mode: 0o700 });
44
- }
45
- if (process.platform !== 'win32') {
46
- try {
47
- fs.chmodSync(STATE_DIR, 0o700);
48
- }
49
- catch { /* best-effort */ }
50
- }
51
- }
52
- catch {
53
- // Best-effort — caller will see write failure later if it matters.
54
- }
55
- }
56
- /** Best-effort lock-down: `0o600` on POSIX, no-op on Windows (NTFS ACL ≠ chmod). */
57
- export function secureFileMode(filePath) {
58
- if (process.platform === 'win32') {
59
- return;
60
- }
61
- try {
62
- fs.chmodSync(filePath, 0o600);
63
- }
64
- catch {
65
- // File may not exist yet, or filesystem may not support chmod.
66
- }
67
- }
68
- /** Atomic write helper — write to temp then rename, never half-written JSON. */
69
- export function atomicWriteJson(targetPath, value, mode = 0o600) {
70
- ensureStateDir();
71
- const parent = path.dirname(targetPath);
72
- try {
73
- if (!fs.existsSync(parent))
74
- fs.mkdirSync(parent, { recursive: true });
75
- }
76
- catch { /* ignore */ }
77
- const tmpPath = `${targetPath}.${process.pid}.${Date.now()}.tmp`;
78
- fs.writeFileSync(tmpPath, JSON.stringify(value, null, 2), 'utf8');
79
- if (process.platform !== 'win32') {
80
- try {
81
- fs.chmodSync(tmpPath, mode);
82
- }
83
- catch { /* ignore */ }
84
- }
85
- fs.renameSync(tmpPath, targetPath);
86
- }
87
- export function loadCliState() {
88
- return readStateUnchecked();
89
- }
90
- export function saveCliState(state) {
91
- atomicWriteJson(STATE_FILE, state);
92
- }
93
- export function getCliStateFile() {
94
- return STATE_FILE;
95
- }
96
- /**
97
- * Offline mode — set VIGTHORIA_OFFLINE=1 to skip every non-essential
98
- * outbound HTTP call. Useful for restricted networks, air-gapped runs,
99
- * and deterministic CI.
100
- */
101
- export function isOfflineMode() {
102
- const flag = String(process.env.VIGTHORIA_OFFLINE || '').trim().toLowerCase();
103
- return flag === '1' || flag === 'true' || flag === 'yes';
104
- }
105
- /** Telemetry opt-out (also implied when offline mode is on). */
106
- export function isTelemetryDisabled() {
107
- if (isOfflineMode())
108
- return true;
109
- const flag = String(process.env.VIGTHORIA_TELEMETRY_DISABLED || '').trim().toLowerCase();
110
- return flag === '1' || flag === 'true' || flag === 'yes';
111
- }
112
- /** When true the startup update check is suppressed (env override or offline). */
113
- export function isUpdateCheckSuppressed() {
114
- if (isOfflineMode())
115
- return true;
116
- const flag = String(process.env.VIGTHORIA_NO_UPDATE_CHECK || '').trim();
117
- return flag === '1';
118
- }
119
- /** Cached read for the latest known version — null when stale or absent. */
120
- export function readCachedLatestVersion(maxAgeMs = UPDATE_CHECK_TTL_MS) {
121
- const state = readStateUnchecked();
122
- const entry = state.updateCheck;
123
- if (!entry || !entry.latestVersion || typeof entry.checkedAt !== 'number') {
124
- return null;
125
- }
126
- if (Date.now() - entry.checkedAt > maxAgeMs) {
127
- return null;
128
- }
129
- return entry.latestVersion;
130
- }
131
- export function writeCachedLatestVersion(latestVersion, notifiedFor) {
132
- try {
133
- const state = readStateUnchecked();
134
- state.updateCheck = {
135
- checkedAt: Date.now(),
136
- latestVersion,
137
- notifiedFor: notifiedFor || state.updateCheck?.notifiedFor,
138
- };
139
- saveCliState(state);
140
- }
141
- catch {
142
- // Caching is a nice-to-have, never block CLI on write failure.
143
- }
144
- }
145
- export function readGatewayPreflightCache(maxAgeMs = GATEWAY_PREFLIGHT_TTL_MS) {
146
- const state = readStateUnchecked();
147
- const entry = state.gatewayPreflight;
148
- if (!entry || typeof entry.checkedAt !== 'number' || typeof entry.valid !== 'boolean') {
149
- return null;
150
- }
151
- if (Date.now() - entry.checkedAt > maxAgeMs) {
152
- return null;
153
- }
154
- return entry.valid;
155
- }
156
- export function writeGatewayPreflightCache(valid) {
157
- try {
158
- const state = readStateUnchecked();
159
- state.gatewayPreflight = { checkedAt: Date.now(), valid };
160
- saveCliState(state);
161
- }
162
- catch {
163
- // Best-effort.
164
- }
165
- }
166
- /**
167
- * Validate an npm package spec used by `vigthoria update --from <spec>`.
168
- * Returns `true` when the spec is acceptable. Rejects whitespace and
169
- * shell metacharacters so the spec can never break out of `execFile` /
170
- * a Windows `shell:true` fallback into command injection.
171
- */
172
- const NPM_SPEC_ALLOWLIST = /^[A-Za-z0-9_./@:+\\=-]+$/;
173
- const DISALLOWED_SHELL_CHARS = /[;&|`$<>(){}\[\]"'\s]/;
174
- export function isSafeNpmPackageSpec(spec) {
175
- const candidate = String(spec || '').trim();
176
- if (!candidate)
177
- return false;
178
- if (candidate.length > 512)
179
- return false;
180
- if (DISALLOWED_SHELL_CHARS.test(candidate))
181
- return false;
182
- if (!NPM_SPEC_ALLOWLIST.test(candidate))
183
- return false;
184
- return true;
185
- }
@@ -1,85 +0,0 @@
1
- /**
2
- * Configuration Manager for Vigthoria CLI
3
- */
4
- export interface VigthoriaCLIConfig {
5
- apiUrl: string;
6
- modelsApiUrl: string;
7
- wsUrl: string;
8
- selfHostedModelsApiUrl: string | null;
9
- authToken: string | null;
10
- refreshToken: string | null;
11
- userId: string | null;
12
- email: string | null;
13
- v3ServiceKey: string | null;
14
- subscription: {
15
- plan: string | null;
16
- status: string | null;
17
- expiresAt: string | null;
18
- };
19
- preferences: {
20
- defaultModel: string;
21
- theme: 'dark' | 'light';
22
- autoApplyFixes: boolean;
23
- showDiffs: boolean;
24
- contextLines: number;
25
- maxTokens: number;
26
- };
27
- project: {
28
- rootPath: string | null;
29
- ignorePatterns: string[];
30
- };
31
- persona: 'default' | 'wiener_grant';
32
- hubModelPrefs?: {
33
- enabledCloudModels: string[];
34
- defaultCloudModel?: string;
35
- defaultLocalModel?: string;
36
- balance?: number;
37
- fetchedAt?: string;
38
- };
39
- }
40
- export interface AvailableModelDescriptor {
41
- id: string;
42
- name: string;
43
- description: string;
44
- tier: string;
45
- backendModel: string;
46
- }
47
- export declare class Config {
48
- private store;
49
- private static readonly OPERATOR_PLANS;
50
- private static readonly CLOUD_PLANS;
51
- constructor();
52
- /**
53
- * Re-apply secure POSIX permissions to the on-disk config file. Safe
54
- * to call repeatedly; no-op on Windows.
55
- */
56
- secureOnDisk(): void;
57
- get<K extends keyof VigthoriaCLIConfig>(key: K): VigthoriaCLIConfig[K];
58
- set<K extends keyof VigthoriaCLIConfig>(key: K, value: VigthoriaCLIConfig[K]): void;
59
- getAll(): VigthoriaCLIConfig;
60
- reset(): void;
61
- isAuthenticated(): boolean;
62
- hasValidSubscription(): boolean;
63
- getNormalizedPlan(): string;
64
- hasOperatorAccess(): boolean;
65
- hasCloudAccess(): boolean;
66
- getConfigPath(): string;
67
- setAuth(data: {
68
- token: string;
69
- refreshToken?: string;
70
- userId: string;
71
- email: string;
72
- }): void;
73
- clearAuth(): void;
74
- setSubscription(data: {
75
- plan: string;
76
- status: string;
77
- expiresAt?: string;
78
- }): void;
79
- getAvailableModels(): AvailableModelDescriptor[];
80
- refreshHubModelPreferences(): Promise<void>;
81
- isCloudModel(modelId: string): boolean;
82
- filterModelsByHubPreferences(models: AvailableModelDescriptor[], enabledCloudModels?: string[]): AvailableModelDescriptor[];
83
- isComplexTask(prompt: string): boolean;
84
- shouldUseCloudForHeavyTask(prompt: string): boolean;
85
- }
@@ -1,267 +0,0 @@
1
- /**
2
- * Configuration Manager for Vigthoria CLI
3
- */
4
- import Conf from 'conf';
5
- import { secureFileMode } from './cli-state.js';
6
- const defaultConfig = {
7
- apiUrl: 'https://coder.vigthoria.io',
8
- modelsApiUrl: 'https://api.vigthoria.io', // Direct AI Models API - no proxying through Coder
9
- wsUrl: 'wss://coder.vigthoria.io/ws',
10
- selfHostedModelsApiUrl: null,
11
- authToken: null,
12
- refreshToken: null,
13
- userId: null,
14
- email: null,
15
- v3ServiceKey: null,
16
- subscription: {
17
- plan: null,
18
- status: null,
19
- expiresAt: null,
20
- },
21
- preferences: {
22
- defaultModel: 'code',
23
- theme: 'dark',
24
- autoApplyFixes: false,
25
- showDiffs: true,
26
- contextLines: 3,
27
- maxTokens: 4096,
28
- },
29
- persona: 'default',
30
- project: {
31
- rootPath: null,
32
- ignorePatterns: [
33
- 'node_modules',
34
- '.git',
35
- 'dist',
36
- 'build',
37
- '__pycache__',
38
- '.venv',
39
- 'venv',
40
- '.env',
41
- '*.log',
42
- ],
43
- },
44
- };
45
- export class Config {
46
- store;
47
- static OPERATOR_PLANS = new Set(['enterprise', 'admin', 'master_admin']);
48
- static CLOUD_PLANS = new Set(['pro', 'professional', 'ultra', 'enterprise', 'master_admin', 'admin']);
49
- constructor() {
50
- // `Conf` defaults to 0o644 on POSIX which would leave auth tokens
51
- // readable by every local user. We post-process the file in
52
- // `secureOnDisk()` to enforce 0o600 ownership. The `fileMode`
53
- // option exists on newer `conf` releases — supply it via a cast so
54
- // older type-defs do not reject the field.
55
- this.store = new Conf({
56
- projectName: 'vigthoria-cli',
57
- defaults: defaultConfig,
58
- ...{ fileMode: 0o600 },
59
- schema: {
60
- apiUrl: { type: 'string' },
61
- modelsApiUrl: { type: 'string' },
62
- wsUrl: { type: 'string' },
63
- selfHostedModelsApiUrl: { type: ['string', 'null'] },
64
- authToken: { type: ['string', 'null'] },
65
- refreshToken: { type: ['string', 'null'] },
66
- userId: { type: ['string', 'null'] },
67
- email: { type: ['string', 'null'] },
68
- v3ServiceKey: { type: ['string', 'null'] },
69
- subscription: {
70
- type: 'object',
71
- properties: {
72
- plan: { type: ['string', 'null'] },
73
- status: { type: ['string', 'null'] },
74
- expiresAt: { type: ['string', 'null'] },
75
- },
76
- },
77
- preferences: {
78
- type: 'object',
79
- properties: {
80
- defaultModel: { type: 'string' },
81
- theme: { type: 'string', enum: ['dark', 'light'] },
82
- autoApplyFixes: { type: 'boolean' },
83
- showDiffs: { type: 'boolean' },
84
- contextLines: { type: 'number' },
85
- maxTokens: { type: 'number' },
86
- },
87
- },
88
- persona: { type: 'string', enum: ['default', 'wiener_grant'] },
89
- project: {
90
- type: 'object',
91
- properties: {
92
- rootPath: { type: ['string', 'null'] },
93
- ignorePatterns: { type: 'array', items: { type: 'string' } },
94
- },
95
- },
96
- },
97
- });
98
- // Defence-in-depth: re-apply 0600 every time we instantiate Config so
99
- // that an older install which created the file with 0644 gets locked
100
- // down on next startup.
101
- try {
102
- secureFileMode(this.store.path);
103
- }
104
- catch { /* best-effort */ }
105
- }
106
- /**
107
- * Re-apply secure POSIX permissions to the on-disk config file. Safe
108
- * to call repeatedly; no-op on Windows.
109
- */
110
- secureOnDisk() {
111
- try {
112
- secureFileMode(this.store.path);
113
- }
114
- catch { /* best-effort */ }
115
- }
116
- get(key) {
117
- return this.store.get(key);
118
- }
119
- set(key, value) {
120
- this.store.set(key, value);
121
- }
122
- getAll() {
123
- return this.store.store;
124
- }
125
- reset() {
126
- this.store.clear();
127
- }
128
- isAuthenticated() {
129
- return this.store.get('authToken') !== null;
130
- }
131
- hasValidSubscription() {
132
- const sub = this.store.get('subscription');
133
- if (!sub.status || sub.status !== 'active')
134
- return false;
135
- if (sub.expiresAt) {
136
- const expires = new Date(sub.expiresAt);
137
- return expires > new Date();
138
- }
139
- return true;
140
- }
141
- getNormalizedPlan() {
142
- return (this.store.get('subscription').plan || '').trim().toLowerCase();
143
- }
144
- hasOperatorAccess() {
145
- return Config.OPERATOR_PLANS.has(this.getNormalizedPlan());
146
- }
147
- hasCloudAccess() {
148
- return Config.CLOUD_PLANS.has(this.getNormalizedPlan());
149
- }
150
- getConfigPath() {
151
- return this.store.path;
152
- }
153
- // Auth helpers
154
- setAuth(data) {
155
- this.store.set('authToken', data.token);
156
- if (data.refreshToken) {
157
- this.store.set('refreshToken', data.refreshToken);
158
- }
159
- this.store.set('userId', data.userId);
160
- this.store.set('email', data.email);
161
- // Tighten permissions whenever the token rotates so a brand-new
162
- // install (which may have created the file under a previous default
163
- // umask) becomes 0600 immediately after first login.
164
- this.secureOnDisk();
165
- }
166
- clearAuth() {
167
- this.store.set('authToken', null);
168
- this.store.set('refreshToken', null);
169
- this.store.set('userId', null);
170
- this.store.set('email', null);
171
- this.store.set('subscription', {
172
- plan: null,
173
- status: null,
174
- expiresAt: null,
175
- });
176
- }
177
- setSubscription(data) {
178
- this.store.set('subscription', {
179
- plan: data.plan,
180
- status: data.status,
181
- expiresAt: data.expiresAt || null,
182
- });
183
- }
184
- // Model selection - Vigthoria Models (internal routing IDs only)
185
- getAvailableModels() {
186
- const sub = this.store.get('subscription');
187
- const plan = (sub.plan || '').toLowerCase();
188
- // ═══════════════════════════════════════════════════════════════
189
- // Vigthoria server infrastructure operational models
190
- // ═══════════════════════════════════════════════════════════════
191
- const models = [
192
- { id: 'code', name: 'Vigthoria v3 Code 35B', description: 'Native 35B coding model on Blackwell (V3 pipeline)', tier: 'local', backendModel: 'vigthoria-v3-code-35b' },
193
- { id: 'code-35b', name: 'Vigthoria v3 Code 35B', description: 'Same flagship model as code', tier: 'local', backendModel: 'vigthoria-v3-code-35b' },
194
- { id: 'code-9b', name: 'Vigthoria v3 Code 9B', description: 'Efficient coding specialist for quick tasks', tier: 'local', backendModel: 'vigthoria-v3-code-9b' },
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' },
197
- ];
198
- if (this.hasCloudAccess()) {
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);
206
- }
207
- return models;
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
- }
236
- // Check if a model is a "Cloud" tier model
237
- isCloudModel(modelId) {
238
- const cloudModels = ['cloud-fast', 'cloud-balanced', 'cloud-code', 'cloud-power', 'cloud-maximum', 'cloud', 'cloud-reason', 'ultra'];
239
- return cloudModels.includes(modelId) || modelId.includes('cloud');
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
- }
247
- // Check if task is complex enough to suggest Cloud upgrade
248
- isComplexTask(prompt) {
249
- const complexIndicators = [
250
- /refactor/i, /architect/i, /redesign/i, /migrate/i,
251
- /multi.?file/i, /multiple files/i, /entire.*project/i,
252
- /all files/i, /whole.*codebase/i, /implement.*feature/i,
253
- /create.*system/i, /build.*from.*scratch/i,
254
- /analyze.*project/i, /review.*codebase/i,
255
- /audit.*project/i, /audit.*workspace/i,
256
- /full overview/i, /analyse.*workspace/i,
257
- /analy[sz]e.*entire/i, /deep audit/i,
258
- ];
259
- return complexIndicators.some(pattern => pattern.test(prompt));
260
- }
261
- shouldUseCloudForHeavyTask(prompt) {
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;
266
- }
267
- }