vigthoria-cli 1.9.22 → 1.10.1

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.
@@ -40,6 +40,8 @@ export declare class ChatCommand {
40
40
  private savePlanToVigFlow;
41
41
  private jsonOutput;
42
42
  private modelGovernanceFallback;
43
+ private retryPromptSignature;
44
+ private retryPromptStreak;
43
45
  private lastAgentRunOutcome;
44
46
  private isJwtExpirationError;
45
47
  private isNetworkError;
@@ -155,10 +157,7 @@ export declare class ChatCommand {
155
157
  * Resumes only the failed/unfinished tasks from the previous run.
156
158
  */
157
159
  private buildRetryPrompt;
158
- /**
159
- * Build the prompt sent to the agent when the user types `/continue`.
160
- * Tells the agent to keep working from the current workspace state.
161
- */
160
+ private computeRetryPromptSignature;
162
161
  private buildContinuePrompt;
163
162
  /**
164
163
  * Re-print the last agent run summary, or guide the user when there isn't one.
@@ -175,6 +174,7 @@ export declare class ChatCommand {
175
174
  private workspaceContainsHtmlEntry;
176
175
  private shouldBypassDirectSingleFileFlow;
177
176
  private shouldPreferLocalAgentLoop;
177
+ private getRuntimeEnvironmentContext;
178
178
  private shouldRequireV3AgentWorkflow;
179
179
  private isServerBindableWorkspace;
180
180
  private isProtectedFileReferenceSafe;
@@ -59,6 +59,8 @@ export class ChatCommand {
59
59
  savePlanToVigFlow = false;
60
60
  jsonOutput = false;
61
61
  modelGovernanceFallback = null;
62
+ retryPromptSignature = null;
63
+ retryPromptStreak = 0;
62
64
  // Last completed Agent run — used by /retry, /continue, and the final summary block.
63
65
  lastAgentRunOutcome = null;
64
66
  isJwtExpirationError(error) {
@@ -381,15 +383,22 @@ export class ChatCommand {
381
383
  }
382
384
  buildTaskShapingInstructions(prompt) {
383
385
  const instructions = [];
386
+ const runtime = this.getRuntimeEnvironmentContext();
384
387
  // Platform-aware routing hints
385
- if (os.platform() === 'win32') {
388
+ if (runtime.platform === 'windows') {
386
389
  instructions.push('Platform: Windows. Use list_dir, glob, read_file, and the grep tool for searching.', 'The grep tool handles Windows automatically — do not use bash to call grep, findstr, or Select-String manually.', 'Do not use bash for Unix commands (cat, head, tail, awk, sed, wc).', 'Use read_file to inspect file contents instead of shell commands.', 'All file paths use forward slashes internally.');
387
390
  }
391
+ else if (runtime.platform === 'macos') {
392
+ instructions.push('Platform: macOS. Prefer list_dir, grep, and read_file tools for deterministic results.', 'Use workspace-relative paths and verify file existence before claiming a file is missing.');
393
+ }
394
+ else if (runtime.platform === 'linux') {
395
+ instructions.push('Platform: Linux. Prefer list_dir, grep, and read_file for grounded repository inspection.', 'Use exact file paths from tool output when reporting findings or fixes.');
396
+ }
388
397
  if (this.isDiagnosticPrompt(prompt)) {
389
398
  instructions.push('Diagnostic mode is active.', 'Treat this as a debugging task, not a generic code review or feature request.', 'Start with concrete evidence: logs, runtime errors, config, launch files, and exact symbol references.', 'If log files exist, inspect them before proposing fixes.', 'Do not claim a file, definition, asset, or symbol is missing until you verify that with tools.', 'If a prior diagnosis mentioned a missing symbol or YAML entry, re-check the actual files before repeating it.', 'Prefer grep plus read_file around the exact references involved in the failure.', 'Separate your reasoning into: Evidence, Confirmed Cause, and Remaining Hypotheses.', 'Do not suggest speculative fixes when the current evidence contradicts them.', 'CRITICAL GROUNDING RULE: Every key name, variable name, symbol, or identifier you mention in your final answer MUST appear verbatim in the tool output you received. If a key/symbol does NOT appear in tool output, you MUST NOT mention it as involved in any conflict or issue.', 'CROSS-FILE ATTRIBUTION: When reporting conflicts between two files, a key/symbol is conflicting ONLY if it appears in BOTH files. Read each file carefully and list only the exact keys that appear in the relevant handler/function of EACH file. Do not assume that because one file handles a key, the other file does too.', 'When reporting conflicts between files, cite the exact file name, line number, and the exact string/key from the tool output. Do not paraphrase or substitute key names.', 'Before concluding, re-check: (1) does every key/symbol in my answer actually appear in the evidence I gathered? (2) for each claimed conflict, did I verify the key appears in BOTH files? If not, correct your answer.');
390
399
  }
391
400
  if (this.isBrowserTaskPrompt(prompt)) {
392
- instructions.push('Browser-debug mode is active.', 'Prefer concrete browser evidence such as console errors, network failures, DOM state, and websocket behavior.', 'If a DevTools Bridge is available, use it as the primary browser observability path.');
401
+ instructions.push('Browser-debug mode is active.', 'Prefer concrete browser evidence such as console errors, network failures, DOM state, and websocket behavior.', 'Use the DevTools Bridge only when the user has explicitly enabled it for this run; otherwise ask for permission before requiring local browser tooling.');
393
402
  }
394
403
  if (instructions.length === 0) {
395
404
  return '';
@@ -444,7 +453,9 @@ export class ChatCommand {
444
453
  }
445
454
  }
446
455
  async getPromptRuntimeContext(prompt) {
447
- const runtimeContext = {};
456
+ const runtimeContext = {
457
+ agentRuntime: this.getRuntimeEnvironmentContext(),
458
+ };
448
459
  const brainContext = this.buildProjectBrainRuntimeContext(prompt, this.operatorMode ? 'vigthoria-cli.operator' : this.agentMode ? 'vigthoria-cli.agent' : 'vigthoria-cli.chat');
449
460
  if (brainContext) {
450
461
  runtimeContext.vigthoriaBrain = brainContext;
@@ -452,6 +463,19 @@ export class ChatCommand {
452
463
  if (!this.isBrowserTaskPrompt(prompt)) {
453
464
  return runtimeContext;
454
465
  }
466
+ const devtoolsBridgeAllowed = /^(1|true|yes)$/i.test(String(process.env.VIGTHORIA_DEVTOOLS_BRIDGE_ALLOWED || process.env.VIGTHORIA_BRIDGE_ALLOWED || ''));
467
+ if (!devtoolsBridgeAllowed) {
468
+ if (!this.jsonOutput) {
469
+ console.log(chalk.yellow('Browser task detected. DevTools Bridge is opt-in; the agent will ask before relying on local browser tooling.'));
470
+ }
471
+ return {
472
+ ...runtimeContext,
473
+ browserTask: true,
474
+ devtoolsBridgeAvailable: false,
475
+ devtoolsBridgeAllowed: false,
476
+ devtoolsBridgeEndpoint: null,
477
+ };
478
+ }
455
479
  const bridgeStatus = await this.callApi('Checking DevTools Bridge status', () => this.api.getDevtoolsBridgeStatus(), 0);
456
480
  if (!this.jsonOutput && bridgeStatus.ok) {
457
481
  console.log(chalk.gray(`Browser task detected. DevTools Bridge is reachable at ${bridgeStatus.endpoint}.`));
@@ -463,6 +487,7 @@ export class ChatCommand {
463
487
  ...runtimeContext,
464
488
  browserTask: true,
465
489
  devtoolsBridgeAvailable: bridgeStatus.ok,
490
+ devtoolsBridgeAllowed: true,
466
491
  devtoolsBridgeEndpoint: bridgeStatus.endpoint,
467
492
  };
468
493
  }
@@ -2527,6 +2552,27 @@ export class ChatCommand {
2527
2552
  console.log(chalk.yellow('Nothing to retry — run an agent task first.'));
2528
2553
  continue;
2529
2554
  }
2555
+ const nextSignature = this.computeRetryPromptSignature();
2556
+ if (nextSignature && this.retryPromptSignature === nextSignature) {
2557
+ this.retryPromptStreak += 1;
2558
+ }
2559
+ else {
2560
+ this.retryPromptSignature = nextSignature;
2561
+ this.retryPromptStreak = 1;
2562
+ }
2563
+ if (this.retryPromptStreak >= 3) {
2564
+ const continuePrompt = this.buildContinuePrompt();
2565
+ if (continuePrompt) {
2566
+ console.log(chalk.yellow('Repeated /retry detected with the same failing task set. Escalating to /continue to avoid planner loops.'));
2567
+ if (!this.agentMode) {
2568
+ this.agentMode = true;
2569
+ this.syncInteractiveModeModel('agent');
2570
+ console.log(chalk.gray('Agent mode re-enabled for continuation.'));
2571
+ }
2572
+ await this.runAgentTurn(continuePrompt);
2573
+ continue;
2574
+ }
2575
+ }
2530
2576
  if (!this.agentMode) {
2531
2577
  this.agentMode = true;
2532
2578
  this.syncInteractiveModeModel('agent');
@@ -2681,6 +2727,7 @@ export class ChatCommand {
2681
2727
  const o = this.lastAgentRunOutcome;
2682
2728
  if (!o || !o.prompt)
2683
2729
  return null;
2730
+ const runtime = this.getRuntimeEnvironmentContext();
2684
2731
  const remaining = [...new Set([...o.failedTaskIds, ...o.unfinishedTaskIds])];
2685
2732
  const taskList = remaining.length > 0 ? remaining.join(', ') : '';
2686
2733
  const blockerLine = o.qualityBlockers.length > 0
@@ -2689,15 +2736,27 @@ export class ChatCommand {
2689
2736
  const missingLine = o.qualityMissing.length > 0
2690
2737
  ? `\nMissing pieces: ${o.qualityMissing.slice(0, 6).join(', ')}.`
2691
2738
  : '';
2739
+ const envLine = `\nExecution environment: ${runtime.platform}; machine scope: ${runtime.machineScope}; workspace path: ${runtime.workspacePath}.`;
2740
+ const localPreferenceLine = runtime.machineScope === 'local-machine'
2741
+ ? '\nUse local workspace tools and local filesystem paths first; do not assume server-side workspace access.'
2742
+ : '';
2692
2743
  if (taskList) {
2693
- return `Resume the previous agent run. Re-execute only these tasks and make them pass: ${taskList}.${blockerLine}${missingLine}\nOriginal request was: ${o.prompt}`;
2744
+ return `Resume the previous agent run. Re-execute only these tasks and make them pass: ${taskList}.${blockerLine}${missingLine}${envLine}${localPreferenceLine}\nOriginal request was: ${o.prompt}`;
2694
2745
  }
2695
- return `Retry the previous request and make sure it finishes successfully.${blockerLine}${missingLine}\nOriginal request was: ${o.prompt}`;
2746
+ return `Retry the previous request and make sure it finishes successfully.${blockerLine}${missingLine}${envLine}${localPreferenceLine}\nOriginal request was: ${o.prompt}`;
2747
+ }
2748
+ computeRetryPromptSignature() {
2749
+ const o = this.lastAgentRunOutcome;
2750
+ if (!o) {
2751
+ return null;
2752
+ }
2753
+ const remaining = [...new Set([...o.failedTaskIds, ...o.unfinishedTaskIds])].sort();
2754
+ if (remaining.length === 0) {
2755
+ return null;
2756
+ }
2757
+ const blockers = [...(o.qualityBlockers || [])].slice(0, 3).sort();
2758
+ return `${remaining.join('|')}::${blockers.join('|')}`;
2696
2759
  }
2697
- /**
2698
- * Build the prompt sent to the agent when the user types `/continue`.
2699
- * Tells the agent to keep working from the current workspace state.
2700
- */
2701
2760
  buildContinuePrompt() {
2702
2761
  const o = this.lastAgentRunOutcome;
2703
2762
  if (!o || !o.prompt)
@@ -2743,6 +2802,14 @@ export class ChatCommand {
2743
2802
  else {
2744
2803
  console.log(chalk.gray('No compact session memory summary yet.'));
2745
2804
  }
2805
+ const runtime = this.getRuntimeEnvironmentContext();
2806
+ console.log();
2807
+ console.log(chalk.white('Runtime Environment:'));
2808
+ console.log(chalk.gray(`Platform: ${runtime.platform} (${runtime.osPlatform})`));
2809
+ console.log(chalk.gray(`Machine scope: ${runtime.machineScope}`));
2810
+ console.log(chalk.gray(`Workspace: ${runtime.workspacePath}`));
2811
+ console.log(chalk.gray(`CWD: ${runtime.cwd}`));
2812
+ console.log(chalk.gray(`Server-bindable workspace: ${runtime.serverBindableWorkspace ? 'yes' : 'no'}`));
2746
2813
  this.showProjectMemory();
2747
2814
  }
2748
2815
  showProjectMemory() {
@@ -2904,19 +2971,52 @@ export class ChatCommand {
2904
2971
  if (this.shouldRequireV3AgentWorkflow(prompt)) {
2905
2972
  return false;
2906
2973
  }
2907
- if (!this.directPromptMode) {
2974
+ const forceV3 = /^(1|true|yes)$/i.test(String(process.env.VIGTHORIA_FORCE_V3_AGENT || ''));
2975
+ if (forceV3) {
2908
2976
  return false;
2909
2977
  }
2910
- // Always prefer V3 agent first — it supports workspace hydration for
2911
- // non-server-bindable workspaces (Windows paths, remote machines).
2912
- // The V3 path will fall back to local-agent-loop if V3 is unreachable.
2913
- // This ensures runs get archived for history/replay/fork.
2914
- return false;
2978
+ const runtime = this.getRuntimeEnvironmentContext();
2979
+ // Local machines and non-server-bindable workspaces should run locally first.
2980
+ if (!runtime.serverBindableWorkspace) {
2981
+ return true;
2982
+ }
2983
+ // Interactive sessions should prioritize local edits unless V3 is explicitly forced.
2984
+ if (!this.directPromptMode) {
2985
+ return true;
2986
+ }
2987
+ // For direct prompts on server-bindable Linux roots, keep V3-first behavior.
2988
+ return runtime.platform !== 'linux';
2989
+ }
2990
+ getRuntimeEnvironmentContext() {
2991
+ const osPlatform = os.platform();
2992
+ const platform = osPlatform === 'win32'
2993
+ ? 'windows'
2994
+ : osPlatform === 'darwin'
2995
+ ? 'macos'
2996
+ : osPlatform === 'linux'
2997
+ ? 'linux'
2998
+ : 'unknown';
2999
+ const workspacePath = this.currentProjectPath || process.cwd();
3000
+ const serverBindableWorkspace = this.isServerBindableWorkspace(workspacePath);
3001
+ return {
3002
+ osPlatform,
3003
+ platform,
3004
+ nodeVersion: process.version,
3005
+ cwd: process.cwd(),
3006
+ workspacePath,
3007
+ directPromptMode: this.directPromptMode,
3008
+ serverBindableWorkspace,
3009
+ machineScope: serverBindableWorkspace ? 'server-workspace' : 'local-machine',
3010
+ };
2915
3011
  }
2916
3012
  shouldRequireV3AgentWorkflow(prompt) {
2917
3013
  if (!this.directPromptMode) {
2918
3014
  return false;
2919
3015
  }
3016
+ const runtime = this.getRuntimeEnvironmentContext();
3017
+ if (runtime.machineScope === 'local-machine') {
3018
+ return false;
3019
+ }
2920
3020
  if (this.inferTargetFilesFromPrompt(prompt).length > 0) {
2921
3021
  return false;
2922
3022
  }
@@ -9,12 +9,20 @@ interface ConfigOptions {
9
9
  list?: boolean;
10
10
  reset?: boolean;
11
11
  }
12
+ interface InitOptions {
13
+ model?: string;
14
+ ignorePatterns?: string;
15
+ autoApplyFixes?: boolean;
16
+ profile?: 'safe' | 'balanced' | 'fast';
17
+ yes?: boolean;
18
+ nonInteractive?: boolean;
19
+ }
12
20
  export declare class ConfigCommand {
13
21
  private config;
14
22
  private logger;
15
23
  constructor(config: Config, logger: Logger);
16
24
  run(options: ConfigOptions): Promise<void>;
17
- init(): Promise<void>;
25
+ init(options?: InitOptions): Promise<void>;
18
26
  private setConfig;
19
27
  private formatConfigValueForDisplay;
20
28
  private redactConfigUrl;
@@ -33,56 +33,93 @@ export class ConfigCommand {
33
33
  // Interactive mode
34
34
  await this.interactiveConfig();
35
35
  }
36
- async init() {
36
+ async init(options = {}) {
37
37
  console.log();
38
38
  console.log(chalk.cyan(`${CH.hDouble.repeat(3)} Initialize Vigthoria in Project ${CH.hDouble.repeat(3)}`));
39
39
  console.log();
40
40
  const cwd = process.cwd();
41
41
  const configFile = path.join(cwd, '.vigthoria.json');
42
+ const allowedModels = new Set(['code', 'code-35b', 'code-9b', 'balanced', 'balanced-4b']);
43
+ const hasOverrides = Boolean(options.model ||
44
+ options.ignorePatterns !== undefined ||
45
+ options.autoApplyFixes !== undefined ||
46
+ options.profile);
47
+ const nonInteractive = Boolean(options.nonInteractive || options.yes || hasOverrides);
42
48
  if (fs.existsSync(configFile)) {
43
- const { overwrite } = await inquirer.prompt([
49
+ if (nonInteractive) {
50
+ if (!options.yes) {
51
+ this.logger.error('.vigthoria.json already exists. Re-run with --yes to overwrite in non-interactive mode.');
52
+ return;
53
+ }
54
+ }
55
+ else {
56
+ const { overwrite } = await inquirer.prompt([
57
+ {
58
+ type: 'confirm',
59
+ name: 'overwrite',
60
+ message: '.vigthoria.json already exists. Overwrite?',
61
+ default: false,
62
+ },
63
+ ]);
64
+ if (!overwrite) {
65
+ this.logger.info('Initialization cancelled');
66
+ return;
67
+ }
68
+ }
69
+ }
70
+ let settings;
71
+ if (nonInteractive) {
72
+ const profileDefaults = {
73
+ safe: { defaultModel: 'balanced', autoApplyFixes: false },
74
+ balanced: { defaultModel: 'code', autoApplyFixes: false },
75
+ fast: { defaultModel: 'code-9b', autoApplyFixes: true },
76
+ };
77
+ const profile = options.profile && profileDefaults[options.profile] ? options.profile : 'balanced';
78
+ const defaults = profileDefaults[profile];
79
+ const model = options.model || defaults.defaultModel;
80
+ if (!allowedModels.has(model)) {
81
+ this.logger.error(`Invalid --model: ${model}`);
82
+ this.logger.info('Allowed values: code, code-35b, code-9b, balanced, balanced-4b');
83
+ return;
84
+ }
85
+ settings = {
86
+ defaultModel: model,
87
+ ignorePatterns: options.ignorePatterns || '',
88
+ autoApplyFixes: options.autoApplyFixes !== undefined ? options.autoApplyFixes : defaults.autoApplyFixes,
89
+ };
90
+ }
91
+ else {
92
+ // Gather project settings interactively
93
+ settings = await inquirer.prompt([
94
+ {
95
+ type: 'list',
96
+ name: 'defaultModel',
97
+ message: 'Default AI model:',
98
+ choices: [
99
+ { name: '═══ Code Models ═══', disabled: true },
100
+ { name: 'Vigthoria v3 Code 35B - Flagship coding model', value: 'code' },
101
+ { name: 'Vigthoria v3 Code 35B - Explicit 35B selection', value: 'code-35b' },
102
+ { name: 'Vigthoria v3 Code 9B - Fast coding specialist', value: 'code-9b' },
103
+ { name: '═══ General Models ═══', disabled: true },
104
+ { name: 'Vigthoria Master 7.6B - Balanced general model', value: 'balanced' },
105
+ { name: 'Vigthoria v3 Balanced 4B - Efficient general purpose', value: 'balanced-4b' },
106
+ ],
107
+ default: 'code',
108
+ },
109
+ {
110
+ type: 'input',
111
+ name: 'ignorePatterns',
112
+ message: 'Additional ignore patterns (comma-separated):',
113
+ default: '',
114
+ },
44
115
  {
45
116
  type: 'confirm',
46
- name: 'overwrite',
47
- message: '.vigthoria.json already exists. Overwrite?',
117
+ name: 'autoApplyFixes',
118
+ message: 'Auto-apply fixes without confirmation?',
48
119
  default: false,
49
120
  },
50
121
  ]);
51
- if (!overwrite) {
52
- this.logger.info('Initialization cancelled');
53
- return;
54
- }
55
122
  }
56
- // Gather project settings
57
- const settings = await inquirer.prompt([
58
- {
59
- type: 'list',
60
- name: 'defaultModel',
61
- message: 'Default AI model:',
62
- choices: [
63
- { name: '═══ Code Models ═══', disabled: true },
64
- { name: 'Vigthoria v3 Code 35B - Flagship coding model', value: 'code' },
65
- { name: 'Vigthoria v3 Code 35B - Explicit 35B selection', value: 'code-35b' },
66
- { name: 'Vigthoria v3 Code 9B - Fast coding specialist', value: 'code-9b' },
67
- { name: '═══ General Models ═══', disabled: true },
68
- { name: 'Vigthoria Master 7.6B - Balanced general model', value: 'balanced' },
69
- { name: 'Vigthoria v3 Balanced 4B - Efficient general purpose', value: 'balanced-4b' },
70
- ],
71
- default: 'code',
72
- },
73
- {
74
- type: 'input',
75
- name: 'ignorePatterns',
76
- message: 'Additional ignore patterns (comma-separated):',
77
- default: '',
78
- },
79
- {
80
- type: 'confirm',
81
- name: 'autoApplyFixes',
82
- message: 'Auto-apply fixes without confirmation?',
83
- default: false,
84
- },
85
- ]);
86
123
  // Create project config
87
124
  const projectConfig = {
88
125
  defaultModel: settings.defaultModel,
@@ -104,7 +141,10 @@ export class ConfigCommand {
104
141
  }
105
142
  }
106
143
  console.log();
107
- console.log(chalk.gray('Project initialized! Run `vigthoria chat` or `npx vigthoria-chat` to start.'));
144
+ if (nonInteractive) {
145
+ console.log(chalk.gray('Project initialized in non-interactive mode.'));
146
+ }
147
+ console.log(chalk.gray('Project initialized! Run vigthoria start for a beginner guide or vigthoria chat to begin.'));
108
148
  console.log();
109
149
  }
110
150
  setConfig(keyValue) {
package/dist/index.js CHANGED
@@ -1357,6 +1357,41 @@ Examples:
1357
1357
  }
1358
1358
  process.exitCode = 0;
1359
1359
  });
1360
+ // Start command - beginner quick guide
1361
+ program
1362
+ .command('start')
1363
+ .alias('guide')
1364
+ .description('Show beginner quick-start steps and recommended first commands')
1365
+ .option('--json', 'Emit machine-readable guide output', false)
1366
+ .action(async (options) => {
1367
+ const steps = [
1368
+ '1. Authenticate: vigthoria login',
1369
+ '2. Verify account: vigthoria status',
1370
+ '3. Initialize project: vigthoria init',
1371
+ '4. Start coding: vigthoria chat --agent',
1372
+ '5. Check for updates: vigthoria update --check',
1373
+ ];
1374
+ if (options.json) {
1375
+ console.log(JSON.stringify({
1376
+ command: 'start',
1377
+ steps,
1378
+ tips: [
1379
+ 'Use vigthoria init --non-interactive for CI/bootstrap scripts.',
1380
+ 'Run vigthoria doctor when environment checks fail.',
1381
+ ],
1382
+ }, null, 2));
1383
+ }
1384
+ else {
1385
+ console.log();
1386
+ console.log(chalk.bold('Vigthoria quick start'));
1387
+ for (const step of steps) {
1388
+ console.log(chalk.gray('- ' + step));
1389
+ }
1390
+ console.log();
1391
+ console.log(chalk.gray('Tip: use vigthoria init --profile safe --non-interactive for conservative defaults.'));
1392
+ }
1393
+ process.exitCode = 0;
1394
+ });
1360
1395
  // Config command
1361
1396
  program
1362
1397
  .command('config')
@@ -1385,7 +1420,6 @@ Examples:
1385
1420
  const manifestUrl = typeof options.manifest === 'string' ? options.manifest.trim() : VIGTHORIA_DEFAULT_MANIFEST_URL.trim();
1386
1421
  const channel = typeof options.channel === 'string' ? options.channel.trim() : 'stable';
1387
1422
  const allowDowngrade = !!options.allowDowngrade;
1388
- const gitPackageSpec = 'git+https://market.vigthoria.io/vigthoria/vigthoria-cli.git';
1389
1423
  if (updateTarget) {
1390
1424
  if (!isSafeNpmPackageSpec(updateTarget)) {
1391
1425
  console.error(chalk.red('Refusing to run installer with unsafe package spec.'));
@@ -1483,7 +1517,7 @@ Examples:
1483
1517
  }
1484
1518
  catch (error) {
1485
1519
  console.error(chalk.red('Failed to process manifest update:'), error.message);
1486
- console.log(chalk.gray('Falling back to npm/git update channels...'));
1520
+ console.log(chalk.gray('Falling back to npm registry update channel...'));
1487
1521
  }
1488
1522
  }
1489
1523
  if (isOfflineMode()) {
@@ -1518,21 +1552,11 @@ Examples:
1518
1552
  catch (error) {
1519
1553
  console.error(chalk.red('Failed to check/install via npm registry:'), error.message);
1520
1554
  if (options.check) {
1521
- console.log(chalk.gray(`npm registry check failed; fallback install target is ${gitPackageSpec}`));
1555
+ console.log(chalk.gray('npm registry check failed. Try again later or use --manifest with a valid release manifest URL.'));
1522
1556
  return;
1523
1557
  }
1524
- try {
1525
- console.log(chalk.cyan('Attempting git package fallback...'));
1526
- await installGlobalPackageWithNpm(gitPackageSpec);
1527
- console.log(chalk.green('Updated via git package fallback'));
1528
- console.log(chalk.gray('Please restart the CLI to use the new version'));
1529
- }
1530
- catch (fallbackError) {
1531
- console.error(chalk.red('Fallback update also failed:'), fallbackError.message);
1532
- console.log(chalk.gray('Try manually: npm install -g vigthoria-cli@latest'));
1533
- console.log(chalk.gray(`Or: npm install -g ${gitPackageSpec}`));
1534
- process.exitCode = 1;
1535
- }
1558
+ console.log(chalk.gray('Try manually: npm install -g vigthoria-cli@latest'));
1559
+ process.exitCode = 1;
1536
1560
  }
1537
1561
  });
1538
1562
  // Hyper Loop command alias (maps to legion --status for checklist gate 6.9)
@@ -1569,9 +1593,15 @@ Examples:
1569
1593
  program
1570
1594
  .command('init')
1571
1595
  .description('Initialize Vigthoria in current project')
1572
- .action(async () => {
1596
+ .option('--model <model>', 'Default model (code, code-35b, code-9b, balanced, balanced-4b)')
1597
+ .option('--ignore-patterns <patterns>', 'Comma-separated ignore patterns for this project')
1598
+ .option('--auto-apply-fixes', 'Enable auto-apply fixes for this project profile')
1599
+ .option('--profile <preset>', 'Quick preset: safe, balanced, fast')
1600
+ .option('-y, --yes', 'Overwrite existing .vigthoria.json without prompting')
1601
+ .option('--non-interactive', 'Do not prompt; use provided flags/defaults')
1602
+ .action(async (options) => {
1573
1603
  const configCmd = new ConfigCommand(config, logger);
1574
- await configCmd.init();
1604
+ await configCmd.init(options);
1575
1605
  });
1576
1606
  const codingCommandDefinitions = [
1577
1607
  { name: 'edit', description: 'Edit code by describing the desired change', instruction: 'Edit the project according to this request' },
@@ -302,6 +302,8 @@ export declare class APIClient {
302
302
  private resolveAgentTargetPath;
303
303
  private isLikelyWindowsPath;
304
304
  private resolveServerBindableWorkspacePath;
305
+ private buildPublicWorkspaceDescriptor;
306
+ private buildPublicRuntimeEnvironment;
305
307
  private buildLocalWorkspaceSummary;
306
308
  /**
307
309
  * Collect text file contents from the workspace for V3 agent hydration.
package/dist/utils/api.js CHANGED
@@ -1265,13 +1265,22 @@ export class APIClient {
1265
1265
  const localWorkspaceSummary = this.buildLocalWorkspaceSummary(localWorkspacePath);
1266
1266
  const requestedModel = String(resolvedContext.model || resolvedContext.requestedModel || 'agent');
1267
1267
  const resolvedModel = this.resolvePermittedModelId(requestedModel);
1268
+ const localWorkspaceName = localWorkspacePath ? path.basename(localWorkspacePath) : null;
1269
+ const localWorkspaceRef = localWorkspaceName ? `vigthoria://local-workspace/${localWorkspaceName}` : null;
1270
+ const publicRuntimeEnvironment = this.buildPublicRuntimeEnvironment(resolvedContext.agentRuntime, {
1271
+ localWorkspacePath,
1272
+ serverWorkspacePath,
1273
+ });
1268
1274
  // When the server cannot directly access the workspace (e.g. Windows
1269
1275
  // client), use the local path as a hint and flag that the workspace
1270
1276
  // files are provided inline in localWorkspaceSummary.workspaceFiles.
1271
1277
  const effectiveWorkspacePath = serverWorkspacePath || null;
1272
1278
  const needsHydration = !serverWorkspacePath && !!localWorkspacePath;
1273
1279
  const payload = {
1274
- workspace: resolvedContext.workspace || null,
1280
+ workspace: this.buildPublicWorkspaceDescriptor(resolvedContext.workspace, {
1281
+ localWorkspacePath,
1282
+ serverWorkspacePath,
1283
+ }),
1275
1284
  activeFile: resolvedContext.activeFile || null,
1276
1285
  history: resolvedContext.history || [],
1277
1286
  agentTaskType: resolvedContext.agentTaskType || 'general',
@@ -1283,11 +1292,16 @@ export class APIClient {
1283
1292
  executionSurface: resolvedContext.executionSurface || 'cli',
1284
1293
  clientSurface: resolvedContext.clientSurface || 'cli',
1285
1294
  localMachineCapable: resolvedContext.localMachineCapable !== false,
1295
+ runtimeEnvironment: publicRuntimeEnvironment,
1286
1296
  workspacePath: effectiveWorkspacePath,
1287
1297
  projectPath: effectiveWorkspacePath,
1288
1298
  targetPath: effectiveWorkspacePath,
1289
- localWorkspacePath: localWorkspacePath || null,
1290
- localWorkspaceName: localWorkspacePath ? path.basename(localWorkspacePath) : null,
1299
+ // Never send a client-local absolute path to the V3 model boundary.
1300
+ // The server only needs a stable label; file contents are carried by
1301
+ // localWorkspaceSummary.workspaceFiles and hydrated into a temp workspace.
1302
+ localWorkspacePath: serverWorkspacePath ? serverWorkspacePath : localWorkspaceRef,
1303
+ localWorkspaceRef,
1304
+ localWorkspaceName,
1291
1305
  localWorkspaceSummary,
1292
1306
  // Signal to the server that the workspace filesystem is not locally
1293
1307
  // accessible — it must hydrate a temp directory from the provided
@@ -1395,19 +1409,30 @@ export class APIClient {
1395
1409
  || resolvedContext.workspacePath
1396
1410
  || resolvedContext.projectRoot
1397
1411
  || process.cwd();
1412
+ const serverWorkspacePath = this.resolveServerBindableWorkspacePath(resolvedContext);
1413
+ const localWorkspaceName = targetPath ? path.basename(targetPath) : null;
1414
+ const localWorkspaceRef = localWorkspaceName ? `vigthoria://local-workspace/${localWorkspaceName}` : null;
1398
1415
  return JSON.stringify({
1399
- workspace: resolvedContext.workspace || null,
1416
+ workspace: this.buildPublicWorkspaceDescriptor(resolvedContext.workspace, {
1417
+ localWorkspacePath: targetPath,
1418
+ serverWorkspacePath,
1419
+ }),
1400
1420
  activeFile: resolvedContext.activeFile || null,
1401
1421
  history: resolvedContext.history || [],
1402
1422
  agentTaskType: resolvedContext.agentTaskType || 'general',
1403
1423
  executionSurface: resolvedContext.executionSurface || 'cli',
1404
1424
  clientSurface: resolvedContext.clientSurface || 'cli',
1405
1425
  localMachineCapable: resolvedContext.localMachineCapable !== false,
1406
- workspacePath: resolvedContext.workspacePath || targetPath,
1407
- projectPath: resolvedContext.projectPath || targetPath,
1408
- targetPath,
1409
- localWorkspacePath: targetPath,
1410
- localWorkspaceName: targetPath ? path.basename(targetPath) : null,
1426
+ runtimeEnvironment: this.buildPublicRuntimeEnvironment(resolvedContext.agentRuntime, {
1427
+ localWorkspacePath: targetPath,
1428
+ serverWorkspacePath,
1429
+ }),
1430
+ workspacePath: serverWorkspacePath || null,
1431
+ projectPath: serverWorkspacePath || null,
1432
+ targetPath: serverWorkspacePath || null,
1433
+ localWorkspacePath: serverWorkspacePath || localWorkspaceRef,
1434
+ localWorkspaceRef,
1435
+ localWorkspaceName,
1411
1436
  contextId: resolvedContext.contextId,
1412
1437
  traceId: resolvedContext.traceId,
1413
1438
  requestStartedAt: resolvedContext.requestStartedAt,
@@ -1894,6 +1919,7 @@ menu {
1894
1919
  workspacePath: workspacePath || null,
1895
1920
  localWorkspacePath: localWorkspacePath || null,
1896
1921
  localWorkspaceSummary,
1922
+ runtimeEnvironment: executionContext.agentRuntime || null,
1897
1923
  requestStartedAt: executionContext.requestStartedAt,
1898
1924
  subscriptionPlan: this.config.getNormalizedPlan() || null,
1899
1925
  email: this.config.get('email') || null,
@@ -1907,6 +1933,7 @@ menu {
1907
1933
  targetPath: workspacePath || null,
1908
1934
  localWorkspacePath: localWorkspacePath || null,
1909
1935
  localWorkspaceSummary,
1936
+ runtimeEnvironment: executionContext.agentRuntime || null,
1910
1937
  activeFile: executionContext.activeFile || null,
1911
1938
  executionSurface: executionContext.executionSurface || 'cli',
1912
1939
  clientSurface: executionContext.clientSurface || 'cli',
@@ -1999,13 +2026,49 @@ menu {
1999
2026
  }
2000
2027
  return '';
2001
2028
  }
2029
+ buildPublicWorkspaceDescriptor(workspace, paths = {}) {
2030
+ const localName = paths.localWorkspacePath ? path.basename(paths.localWorkspacePath) : null;
2031
+ const isServerBindable = !!paths.serverWorkspacePath;
2032
+ const descriptor = {
2033
+ name: localName,
2034
+ path: isServerBindable ? paths.serverWorkspacePath : (localName ? `vigthoria://local-workspace/${localName}` : null),
2035
+ scheme: isServerBindable ? 'server-bindable' : 'local-workspace',
2036
+ };
2037
+ if (workspace && typeof workspace === 'object') {
2038
+ for (const [key, value] of Object.entries(workspace)) {
2039
+ if (key === 'path' || key === 'workspacePath' || key === 'projectPath' || key === 'targetPath' || key === 'cwd') {
2040
+ continue;
2041
+ }
2042
+ descriptor[key] = value;
2043
+ }
2044
+ }
2045
+ return descriptor.name || descriptor.path ? descriptor : null;
2046
+ }
2047
+ buildPublicRuntimeEnvironment(runtime, paths = {}) {
2048
+ if (!runtime || typeof runtime !== 'object') {
2049
+ return null;
2050
+ }
2051
+ const localName = paths.localWorkspacePath ? path.basename(paths.localWorkspacePath) : null;
2052
+ const serverBindableWorkspace = !!paths.serverWorkspacePath || runtime.serverBindableWorkspace === true;
2053
+ return {
2054
+ osPlatform: runtime.osPlatform || null,
2055
+ platform: runtime.platform || null,
2056
+ nodeVersion: runtime.nodeVersion || null,
2057
+ directPromptMode: runtime.directPromptMode === true,
2058
+ serverBindableWorkspace,
2059
+ machineScope: serverBindableWorkspace ? 'server-workspace' : 'local-machine',
2060
+ workspaceName: localName,
2061
+ workspacePath: serverBindableWorkspace ? paths.serverWorkspacePath || null : (localName ? `vigthoria://local-workspace/${localName}` : null),
2062
+ cwd: serverBindableWorkspace ? paths.serverWorkspacePath || null : (localName ? `vigthoria://local-workspace/${localName}` : null),
2063
+ };
2064
+ }
2002
2065
  buildLocalWorkspaceSummary(rootPath) {
2003
2066
  if (!rootPath || !fs.existsSync(rootPath)) {
2004
2067
  return null;
2005
2068
  }
2006
2069
  try {
2007
2070
  const summary = {
2008
- path: rootPath,
2071
+ path: 'vigthoria://workspace/',
2009
2072
  name: path.basename(rootPath),
2010
2073
  files: [],
2011
2074
  };
@@ -18,7 +18,7 @@ const defaultConfig = {
18
18
  expiresAt: null,
19
19
  },
20
20
  preferences: {
21
- defaultModel: 'code',
21
+ defaultModel: 'agent',
22
22
  theme: 'dark',
23
23
  autoApplyFixes: false,
24
24
  showDiffs: true,
@@ -185,12 +185,12 @@ export class Config {
185
185
  // VIGTHORIA LOCAL - Self-hosted operational models
186
186
  // ═══════════════════════════════════════════════════════════════
187
187
  const models = [
188
- { id: 'agent', name: 'Vigthoria Agent GPU', description: 'Blackwell autonomous agent workflow', tier: 'local', backendModel: 'vigthoria-v3-code-35b' },
188
+ { id: 'agent', name: 'Vigthoria V3 Code Agent', description: 'Blackwell autonomous agent workflow', tier: 'local', backendModel: 'vigthoria-v3-code-35b' },
189
189
  { id: 'code', name: 'Vigthoria v3 Code 35B', description: 'Native 35B coding model on Blackwell', tier: 'local', backendModel: 'vigthoria-v3-code-35b' },
190
190
  { id: 'code-35b', name: 'Vigthoria v3 Code 35B', description: 'Same flagship model as code', tier: 'local', backendModel: 'vigthoria-v3-code-35b' },
191
191
  { 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 v3 Balanced 4B', description: 'Balanced general-purpose local model', tier: 'local', backendModel: 'vigthoria-v3-balanced-4b' },
193
- { id: 'balanced-4b', name: 'Vigthoria v3 Balanced 4B', description: 'Efficient 4B general-purpose model (Qwen3.5-4B based)', tier: 'local', backendModel: 'vigthoria-v3-balanced-4b' },
192
+ { id: 'balanced', name: 'Vigthoria Balanced 4B', description: 'Balanced general-purpose local model', tier: 'local', backendModel: 'vigthoria-v3-balanced-4b' },
193
+ { 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
194
  ];
195
195
  // ═══════════════════════════════════════════════════════════════
196
196
  // VIGTHORIA CLOUD - Premium cloud models (Pro subscription)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vigthoria-cli",
3
- "version": "1.9.22",
3
+ "version": "1.10.1",
4
4
  "description": "Vigthoria Coder CLI - AI-powered terminal coding assistant",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -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:4008/health http://localhost:4011/health; do
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" ]]