vigthoria-cli 1.10.37 → 1.10.48

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/index.js CHANGED
@@ -595,7 +595,7 @@ export async function main(args) {
595
595
  program
596
596
  .command('chat')
597
597
  .alias('c')
598
- .description('Start interactive chat with Vigthoria AI')
598
+ .description('Start interactive chat (agent ON by default; use --no-agent for simple chat)')
599
599
  .option('-m, --model <model>', 'Select AI model (agent, code, code-35b, code-9b, balanced, balanced-4b, cloud, ultra)')
600
600
  .option('-p, --project <path>', 'Set project context path')
601
601
  .option('--new-project [name]', 'Create or use a managed local workspace folder when no --project path is given')
@@ -616,6 +616,7 @@ export async function main(args) {
616
616
  projectProvided: typeof options.project === 'string' && options.project.trim().length > 0,
617
617
  newProject: options.newProject,
618
618
  agent: options.agent,
619
+ agentEntry: options.agent === false ? 'chat-plain' : 'chat-default',
619
620
  workflow: options.workflow,
620
621
  json: options.json,
621
622
  autoApprove: options.autoApprove,
@@ -647,6 +648,7 @@ export async function main(args) {
647
648
  projectProvided: typeof options.project === 'string' && options.project.trim().length > 0,
648
649
  newProject: options.newProject,
649
650
  agent: options.agent,
651
+ agentEntry: options.agent === false ? 'chat-plain' : 'chat-default',
650
652
  workflow: options.workflow,
651
653
  json: options.json,
652
654
  autoApprove: options.autoApprove,
@@ -661,7 +663,7 @@ export async function main(args) {
661
663
  program
662
664
  .command('agent')
663
665
  .alias('a')
664
- .description('Start agentic mode - AI can read/write files, run commands')
666
+ .description('Start full agent session with workspace setup (recommended over /agent in chat)')
665
667
  .option('-m, --model <model>', 'Select AI model (agent, code, cloud, ultra)')
666
668
  .option('-p, --project <path>', 'Set project context path')
667
669
  .option('--new-project [name]', 'Create or use a managed local workspace folder when no --project path is given')
@@ -679,6 +681,7 @@ export async function main(args) {
679
681
  projectProvided: typeof options.project === 'string' && options.project.trim().length > 0,
680
682
  newProject: options.newProject,
681
683
  agent: true,
684
+ agentEntry: 'command',
682
685
  operator: false,
683
686
  workflow: options.workflow,
684
687
  json: options.json,
package/dist/utils/api.js CHANGED
@@ -260,9 +260,12 @@ const DEFAULT_V3_AGENT_TIMEOUT_MS = (() => {
260
260
  return Number.isFinite(parsed) && parsed >= 0 ? parsed : 0;
261
261
  })();
262
262
  const DEFAULT_V3_AGENT_IDLE_TIMEOUT_MS = (() => {
263
- const rawValue = process.env.VIGTHORIA_AGENT_IDLE_TIMEOUT_MS || process.env.V3_AGENT_IDLE_TIMEOUT_MS || '90000';
263
+ const rawValue = process.env.VIGTHORIA_AGENT_IDLE_TIMEOUT_MS || process.env.V3_AGENT_IDLE_TIMEOUT_MS;
264
+ if (!rawValue) {
265
+ return 0;
266
+ }
264
267
  const parsed = Number.parseInt(rawValue, 10);
265
- return Number.isFinite(parsed) && parsed > 0 ? parsed : 90000;
268
+ return Number.isFinite(parsed) && parsed >= 0 ? parsed : 0;
266
269
  })();
267
270
  const DEFAULT_MCP_BIND_TIMEOUT_MS = (() => {
268
271
  const rawValue = process.env.VIGTHORIA_MCP_BIND_TIMEOUT_MS || process.env.MCP_BIND_TIMEOUT_MS || '5000';
@@ -1730,6 +1733,8 @@ export class APIClient {
1730
1733
  && (resolvedContext.executionSurface === 'cli' || resolvedContext.clientSurface === 'cli')
1731
1734
  && !!localWorkspacePath
1732
1735
  && !serverWorkspacePath),
1736
+ approvalLevel: resolvedContext.autoApprove === true ? 'auto' : (resolvedContext.approvalLevel || 'confirm'),
1737
+ allowedCommands: Array.isArray(resolvedContext.allowedCommands) ? resolvedContext.allowedCommands : [],
1733
1738
  clientToolPathRules: (resolvedContext.clientToolExecution === true || (resolvedContext.localMachineCapable !== false
1734
1739
  && (resolvedContext.executionSurface === 'cli' || resolvedContext.clientSurface === 'cli')
1735
1740
  && !!localWorkspacePath
@@ -1746,6 +1751,8 @@ export class APIClient {
1746
1751
  ...(resolvedContext.agentTaskType === 'analysis'
1747
1752
  ? {
1748
1753
  max_iterations: Number.parseInt(process.env.VIGTHORIA_ANALYSIS_MAX_ITERATIONS || '15', 10) || 15,
1754
+ task_kind: 'analysis',
1755
+ requires_file_changes: false,
1749
1756
  analysis_guidance: this.buildAnalysisGuidance(Array.isArray(localWorkspaceSummary?.promptFocusDirectories)
1750
1757
  ? localWorkspaceSummary.promptFocusDirectories
1751
1758
  : [], Array.isArray(localWorkspaceSummary?.mandatoryReadPaths)
@@ -2460,7 +2467,7 @@ menu {
2460
2467
  if (!candidate || !path.isAbsolute(candidate) || !fs.existsSync(candidate)) {
2461
2468
  return '';
2462
2469
  }
2463
- const configuredRoots = (process.env.VIGTHORIA_SERVER_WORKSPACE_ROOTS || '/var/www/vigthoria-user-workspaces,/var/lib/vigthoria-workspaces')
2470
+ const configuredRoots = (process.env.VIGTHORIA_SERVER_WORKSPACE_ROOTS || '/var/www,/var/www/vigthoria-user-workspaces,/var/lib/vigthoria-workspaces')
2464
2471
  .split(',')
2465
2472
  .map((entry) => entry.trim())
2466
2473
  .filter(Boolean);
@@ -2894,8 +2901,8 @@ menu {
2894
2901
  * Budget: up to ~2 MB total, per-file cap 200 KB, skip binary extensions.
2895
2902
  */
2896
2903
  collectWorkspaceFileContents(rootPath, filePaths) {
2897
- const MAX_TOTAL_BYTES = 2 * 1024 * 1024;
2898
- const MAX_FILE_BYTES = 200 * 1024;
2904
+ const MAX_TOTAL_BYTES = Number.parseInt(process.env.VIGTHORIA_WORKSPACE_HYDRATION_MAX_BYTES || '', 10) || (8 * 1024 * 1024);
2905
+ const MAX_FILE_BYTES = Number.parseInt(process.env.VIGTHORIA_WORKSPACE_HYDRATION_MAX_FILE_BYTES || '', 10) || (512 * 1024);
2899
2906
  const BINARY_EXTENSIONS = new Set([
2900
2907
  '.png', '.jpg', '.jpeg', '.gif', '.bmp', '.ico', '.svg', '.webp', '.avif',
2901
2908
  '.mp3', '.mp4', '.wav', '.ogg', '.webm', '.flac', '.aac',
@@ -3129,11 +3136,16 @@ menu {
3129
3136
  streamedFiles[filePath] = args.content;
3130
3137
  return;
3131
3138
  }
3132
- if (event.name === 'edit_file' && typeof args.old_string === 'string' && typeof args.new_string === 'string') {
3133
- const existing = streamedFiles[filePath];
3134
- if (typeof existing === 'string' && existing.includes(args.old_string)) {
3135
- streamedFiles[filePath] = existing.replace(args.old_string, args.new_string);
3139
+ if (event.name === 'edit_file') {
3140
+ const oldString = args.old_string ?? args.old_text;
3141
+ const newString = args.new_string ?? args.new_text;
3142
+ if (typeof oldString === 'string' && typeof newString === 'string') {
3143
+ const existing = streamedFiles[filePath];
3144
+ if (typeof existing === 'string' && existing.includes(oldString)) {
3145
+ streamedFiles[filePath] = existing.replace(oldString, newString);
3146
+ }
3136
3147
  }
3148
+ return;
3137
3149
  }
3138
3150
  }
3139
3151
  }
@@ -4276,6 +4288,36 @@ document.addEventListener('DOMContentLoaded', () => {
4276
4288
  }
4277
4289
  }
4278
4290
  }
4291
+ if (event.type === 'approval_required') {
4292
+ const activeContextId = String(event.context_id || contextId || context.contextId || '').trim();
4293
+ const approvalId = String(event.approval_id || '').trim();
4294
+ const command = String(event.command || '').trim();
4295
+ let approved = context.autoApprove === true;
4296
+ let allowMode = 'once';
4297
+ if (!approved) {
4298
+ const handler = context.onCommandApproval;
4299
+ if (typeof handler === 'function') {
4300
+ try {
4301
+ const decision = await handler(event);
4302
+ if (decision === true) {
4303
+ approved = true;
4304
+ }
4305
+ else if (decision && typeof decision === 'object') {
4306
+ approved = decision.approved === true;
4307
+ allowMode = String(decision.allowMode || decision.allow_mode || 'once');
4308
+ }
4309
+ }
4310
+ catch (error) {
4311
+ approved = false;
4312
+ this.logger?.warn?.(`Command approval prompt failed: ${error?.message || error}`);
4313
+ }
4314
+ }
4315
+ }
4316
+ if (activeContextId && approvalId) {
4317
+ await this.submitCommandApproval(activeContextId, approvalId, approved, command, allowMode, context.v3BackendUrl);
4318
+ }
4319
+ continue;
4320
+ }
4279
4321
  if (typeof context.onStreamEvent === 'function') {
4280
4322
  try {
4281
4323
  context.onStreamEvent(userEvent);
@@ -4388,20 +4430,59 @@ document.addEventListener('DOMContentLoaded', () => {
4388
4430
  const endpoint = /127\.0\.0\.1:8030|localhost:8030/.test(baseUrl)
4389
4431
  ? `${baseUrl}/api/agent/client-tool-result`
4390
4432
  : `${baseUrl}/api/v3-agent/client-tool-result`;
4433
+ const body = JSON.stringify({
4434
+ context_id: trimmedContextId,
4435
+ call_id: trimmedCallId,
4436
+ success: result.success === true,
4437
+ output: String(result.output || ''),
4438
+ error: String(result.error || ''),
4439
+ });
4440
+ for (let attempt = 0; attempt < 3; attempt += 1) {
4441
+ const response = await fetch(endpoint, {
4442
+ method: 'POST',
4443
+ headers: { ...headers, 'Content-Type': 'application/json' },
4444
+ body,
4445
+ });
4446
+ if (response.ok) {
4447
+ return;
4448
+ }
4449
+ const errorText = await response.text().catch(() => '');
4450
+ const isPendingRace = response.status === 404 && /no pending client tool call/i.test(errorText);
4451
+ if (isPendingRace && attempt < 2) {
4452
+ await new Promise((resolve) => setTimeout(resolve, 120 * (attempt + 1)));
4453
+ continue;
4454
+ }
4455
+ throw new Error(`Client tool result rejected (${response.status}): ${sanitizeUserFacingErrorText(errorText).slice(0, 200)}`);
4456
+ }
4457
+ }
4458
+ async submitCommandApproval(contextId, approvalId, approved, command = '', allowMode = 'once', backendUrl) {
4459
+ const trimmedContextId = String(contextId || '').trim();
4460
+ const trimmedApprovalId = String(approvalId || '').trim();
4461
+ if (!trimmedContextId || !trimmedApprovalId) {
4462
+ return;
4463
+ }
4464
+ const baseUrl = String(backendUrl || this.getV3AgentBaseUrls()[0] || '').replace(/\/$/, '');
4465
+ if (!baseUrl) {
4466
+ return;
4467
+ }
4468
+ const headers = await this.getV3AgentHeaders();
4469
+ const endpoint = /127\.0\.0\.1:8030|localhost:8030/.test(baseUrl)
4470
+ ? `${baseUrl}/api/agent/approval`
4471
+ : `${baseUrl}/api/v3-agent/approval`;
4391
4472
  const response = await fetch(endpoint, {
4392
4473
  method: 'POST',
4393
4474
  headers: { ...headers, 'Content-Type': 'application/json' },
4394
4475
  body: JSON.stringify({
4395
4476
  context_id: trimmedContextId,
4396
- call_id: trimmedCallId,
4397
- success: result.success === true,
4398
- output: String(result.output || ''),
4399
- error: String(result.error || ''),
4477
+ approval_id: trimmedApprovalId,
4478
+ approved: approved === true,
4479
+ command: String(command || ''),
4480
+ allow_mode: String(allowMode || 'once'),
4400
4481
  }),
4401
4482
  });
4402
4483
  if (!response.ok) {
4403
4484
  const errorText = await response.text().catch(() => '');
4404
- throw new Error(`Client tool result rejected (${response.status}): ${sanitizeUserFacingErrorText(errorText).slice(0, 200)}`);
4485
+ throw new Error(`Command approval rejected (${response.status}): ${sanitizeUserFacingErrorText(errorText).slice(0, 200)}`);
4405
4486
  }
4406
4487
  }
4407
4488
  async runV3AgentWorkflow(message, context = {}) {
@@ -3120,6 +3120,12 @@ export class AgenticTools {
3120
3120
  'edit_file': 'edit_file',
3121
3121
  'editfile': 'edit_file',
3122
3122
  'edit': 'edit_file',
3123
+ 'search_files': 'grep',
3124
+ 'grep': 'grep',
3125
+ 'glob': 'glob',
3126
+ 'find_files': 'grep',
3127
+ 'run_command': 'bash',
3128
+ 'syntax_check': 'syntax_check',
3123
3129
  };
3124
3130
  return toolMap[normalized] || normalized;
3125
3131
  };
package/package.json CHANGED
@@ -1,8 +1,7 @@
1
1
  {
2
2
  "name": "vigthoria-cli",
3
- "version": "1.10.37",
3
+ "version": "1.10.48",
4
4
  "description": "Vigthoria Coder CLI - AI-powered terminal coding assistant",
5
- "type": "module",
6
5
  "main": "dist/index.js",
7
6
  "files": [
8
7
  "dist",
@@ -65,9 +64,7 @@
65
64
  "test:model:governance": "npm run build && node scripts/test-model-governance-no-agent.js",
66
65
  "validate:no-go": "bash scripts/release/validate-no-go-gates.sh",
67
66
  "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",
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"
67
+ "test:windows:v3-sync": "npm run build && node scripts/test-windows-v3-sync-recovery.js"
71
68
  },
72
69
  "keywords": [
73
70
  "ai",
@@ -84,7 +81,7 @@
84
81
  "archiver": "^6.0.1",
85
82
  "axios": "^1.6.0",
86
83
  "chalk": "^5.3.0",
87
- "chokidar": "^4.0.0",
84
+ "chokidar": "^5.0.0",
88
85
  "commander": "^11.1.0",
89
86
  "conf": "^12.0.0",
90
87
  "diff": "^5.1.0",