vigthoria-cli 1.9.10 → 1.9.20

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 (53) hide show
  1. package/README.md +4 -4
  2. package/dist/commands/auth.js +48 -65
  3. package/dist/commands/bridge.js +12 -19
  4. package/dist/commands/cancel.js +15 -22
  5. package/dist/commands/chat.d.ts +35 -0
  6. package/dist/commands/chat.js +747 -256
  7. package/dist/commands/config.js +31 -71
  8. package/dist/commands/deploy.js +83 -123
  9. package/dist/commands/device.d.ts +35 -0
  10. package/dist/commands/device.js +239 -0
  11. package/dist/commands/edit.js +32 -39
  12. package/dist/commands/explain.js +18 -25
  13. package/dist/commands/fork.js +22 -27
  14. package/dist/commands/generate.js +37 -44
  15. package/dist/commands/history.js +20 -25
  16. package/dist/commands/hub.js +95 -102
  17. package/dist/commands/index.js +41 -46
  18. package/dist/commands/legion.d.ts +1 -0
  19. package/dist/commands/legion.js +162 -209
  20. package/dist/commands/preview.js +60 -98
  21. package/dist/commands/replay.js +27 -32
  22. package/dist/commands/repo.js +103 -141
  23. package/dist/commands/review.js +29 -36
  24. package/dist/commands/security.js +5 -12
  25. package/dist/commands/update.js +15 -49
  26. package/dist/commands/workflow.d.ts +8 -1
  27. package/dist/commands/workflow.js +53 -19
  28. package/dist/index.js +409 -234
  29. package/dist/utils/api.d.ts +5 -0
  30. package/dist/utils/api.js +373 -166
  31. package/dist/utils/bridge-client.js +11 -52
  32. package/dist/utils/cli-state.d.ts +54 -0
  33. package/dist/utils/cli-state.js +185 -0
  34. package/dist/utils/config.d.ts +5 -0
  35. package/dist/utils/config.js +35 -14
  36. package/dist/utils/context-ranker.js +15 -21
  37. package/dist/utils/files.js +5 -42
  38. package/dist/utils/logger.js +42 -50
  39. package/dist/utils/post-write-validator.js +22 -29
  40. package/dist/utils/project-memory.d.ts +56 -0
  41. package/dist/utils/project-memory.js +289 -0
  42. package/dist/utils/session.d.ts +29 -3
  43. package/dist/utils/session.js +137 -85
  44. package/dist/utils/task-display.js +13 -20
  45. package/dist/utils/tools.d.ts +19 -0
  46. package/dist/utils/tools.js +84 -87
  47. package/dist/utils/workspace-cache.js +18 -26
  48. package/dist/utils/workspace-stream.js +26 -64
  49. package/install.ps1 +15 -1
  50. package/install.sh +1 -1
  51. package/package.json +5 -3
  52. package/scripts/release/LOCAL_MACHINE_USER_VERIFICATION.md +1 -1
  53. package/scripts/release/validate-no-go-gates.sh +2 -2
@@ -1,4 +1,3 @@
1
- "use strict";
2
1
  /**
3
2
  * Vigthoria CLI — Multi-Step Terminal Task Display
4
3
  *
@@ -7,27 +6,22 @@
7
6
  *
8
7
  * Only activates when stderr is a real TTY; JSON mode and piped output stay clean.
9
8
  */
10
- var __importDefault = (this && this.__importDefault) || function (mod) {
11
- return (mod && mod.__esModule) ? mod : { "default": mod };
12
- };
13
- Object.defineProperty(exports, "__esModule", { value: true });
14
- exports.TaskDisplay = void 0;
15
- const chalk_1 = __importDefault(require("chalk"));
9
+ import chalk from 'chalk';
16
10
  const ICONS = {
17
- pending: chalk_1.default.gray('○'),
18
- running: chalk_1.default.cyan('⟳'),
19
- done: chalk_1.default.green('✓'),
20
- error: chalk_1.default.red('✗'),
21
- skipped: chalk_1.default.gray('\u2013'),
11
+ pending: chalk.gray('○'),
12
+ running: chalk.cyan('⟳'),
13
+ done: chalk.green('✓'),
14
+ error: chalk.red('✗'),
15
+ skipped: chalk.gray('\u2013'),
22
16
  };
23
17
  const LABEL_FN = {
24
- pending: (s) => chalk_1.default.gray(s),
25
- running: (s) => chalk_1.default.cyan.bold(s),
26
- done: (s) => chalk_1.default.gray(s),
27
- error: (s) => chalk_1.default.red(s),
28
- skipped: (s) => chalk_1.default.gray(s),
18
+ pending: (s) => chalk.gray(s),
19
+ running: (s) => chalk.cyan.bold(s),
20
+ done: (s) => chalk.gray(s),
21
+ error: (s) => chalk.red(s),
22
+ skipped: (s) => chalk.gray(s),
29
23
  };
30
- class TaskDisplay {
24
+ export class TaskDisplay {
31
25
  tasks = [];
32
26
  linesRendered = 0;
33
27
  enabled;
@@ -44,7 +38,7 @@ class TaskDisplay {
44
38
  return this.tasks.map((t) => {
45
39
  const icon = ICONS[t.status];
46
40
  const label = LABEL_FN[t.status](t.label);
47
- const detail = t.detail ? chalk_1.default.gray(` \u2014 ${t.detail.slice(0, 60)}`) : '';
41
+ const detail = t.detail ? chalk.gray(` \u2014 ${t.detail.slice(0, 60)}`) : '';
48
42
  return ` ${icon} ${label}${detail}`;
49
43
  });
50
44
  }
@@ -112,4 +106,3 @@ class TaskDisplay {
112
106
  return this.enabled;
113
107
  }
114
108
  }
115
- exports.TaskDisplay = TaskDisplay;
@@ -34,6 +34,10 @@ export interface ToolResult {
34
34
  suggestion?: string;
35
35
  canRetry?: boolean;
36
36
  undoable?: boolean;
37
+ /** True when VIGTHORIA_DRY_RUN / VIGTHORIA_READ_ONLY caused a mutating tool to short-circuit. */
38
+ dryRun?: boolean;
39
+ /** Optional human-readable message attached to a dry-run / informational result. */
40
+ message?: string;
37
41
  metadata?: {
38
42
  searchStatus?: SearchStatus;
39
43
  [key: string]: any;
@@ -139,6 +143,21 @@ export declare class AgenticTools {
139
143
  * Execute tool with automatic retry for transient failures
140
144
  */
141
145
  private executeWithRetry;
146
+ /**
147
+ * Tool names that mutate the user's filesystem, shell state, or remote
148
+ * services. Used by the dry-run / read-only gate below.
149
+ */
150
+ private static readonly MUTATING_TOOLS;
151
+ /**
152
+ * `VIGTHORIA_DRY_RUN=1` and `VIGTHORIA_READ_ONLY=1` are end-user safety
153
+ * switches: every mutating tool short-circuits with a clear "would have
154
+ * happened" result instead of touching the filesystem or network.
155
+ *
156
+ * The flags are checked at call-time (not at construction time) so they
157
+ * can be flipped per-prompt by users who want to inspect agent intent
158
+ * before committing.
159
+ */
160
+ private isDryRunActive;
142
161
  /**
143
162
  * Execute the actual tool operation
144
163
  */
@@ -1,4 +1,3 @@
1
- "use strict";
2
1
  /**
3
2
  * Vigthoria CLI Tools - Agentic Tool System
4
3
  *
@@ -14,52 +13,17 @@
14
13
  * @version 1.1.0
15
14
  * @author Vigthoria Labs
16
15
  */
17
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
18
- if (k2 === undefined) k2 = k;
19
- var desc = Object.getOwnPropertyDescriptor(m, k);
20
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
21
- desc = { enumerable: true, get: function() { return m[k]; } };
22
- }
23
- Object.defineProperty(o, k2, desc);
24
- }) : (function(o, m, k, k2) {
25
- if (k2 === undefined) k2 = k;
26
- o[k2] = m[k];
27
- }));
28
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
29
- Object.defineProperty(o, "default", { enumerable: true, value: v });
30
- }) : function(o, v) {
31
- o["default"] = v;
32
- });
33
- var __importStar = (this && this.__importStar) || (function () {
34
- var ownKeys = function(o) {
35
- ownKeys = Object.getOwnPropertyNames || function (o) {
36
- var ar = [];
37
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
38
- return ar;
39
- };
40
- return ownKeys(o);
41
- };
42
- return function (mod) {
43
- if (mod && mod.__esModule) return mod;
44
- var result = {};
45
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
46
- __setModuleDefault(result, mod);
47
- return result;
48
- };
49
- })();
50
- var __importDefault = (this && this.__importDefault) || function (mod) {
51
- return (mod && mod.__esModule) ? mod : { "default": mod };
52
- };
53
- Object.defineProperty(exports, "__esModule", { value: true });
54
- exports.AgenticTools = exports.ToolErrorType = void 0;
55
- exports.installUpdateWindows = installUpdateWindows;
56
- exports.robustifyStreamResponse = robustifyStreamResponse;
57
- const fs = __importStar(require("fs"));
58
- const path = __importStar(require("path"));
59
- const child_process_1 = require("child_process");
60
- const chalk_1 = __importDefault(require("chalk"));
61
- const logger_js_1 = require("./logger.js");
62
- const api_js_1 = require("./api.js");
16
+ import * as fs from 'fs';
17
+ import * as path from 'path';
18
+ import { execSync, spawn } from 'child_process';
19
+ import { createRequire } from 'node:module';
20
+ import chalk from 'chalk';
21
+ // ESM shim — re-create CommonJS-style `require()` so the inline
22
+ // `require('os')` / `require('minimatch')` / `require('glob')` calls
23
+ // inside lazy code paths continue to work unchanged in ESM mode.
24
+ const require = createRequire(import.meta.url);
25
+ import { CH } from './logger.js';
26
+ import { isServerRuntime } from './api.js';
63
27
  const STREAM_RESPONSE_MAX_YIELD_CHARS = 32 * 1024;
64
28
  const POWERSHELL_SAFE_PATH_PATTERN = /^[A-Za-z0-9_:\\/.\-\s]+$/;
65
29
  const POWERSHELL_SAFE_INCLUDE_PATTERN = /^[A-Za-z0-9_*?.\-]+$/;
@@ -91,7 +55,7 @@ function resolveWindowsInstallerPath() {
91
55
  ];
92
56
  return candidates.find((candidate) => fs.existsSync(candidate)) ?? candidates[0];
93
57
  }
94
- async function installUpdateWindows() {
58
+ export async function installUpdateWindows() {
95
59
  const installerPath = resolveWindowsInstallerPath();
96
60
  try {
97
61
  if (!fs.existsSync(installerPath)) {
@@ -99,7 +63,7 @@ async function installUpdateWindows() {
99
63
  }
100
64
  await fs.promises.access(installerPath, fs.constants.F_OK);
101
65
  await new Promise((resolve, reject) => {
102
- const child = (0, child_process_1.spawn)(installerPath, [], {
66
+ const child = spawn(installerPath, [], {
103
67
  cwd: path.dirname(installerPath),
104
68
  detached: true,
105
69
  stdio: 'ignore',
@@ -121,7 +85,7 @@ async function installUpdateWindows() {
121
85
  return { success: false, platform: 'windows', error: message };
122
86
  }
123
87
  }
124
- async function* robustifyStreamResponse(res) {
88
+ export async function* robustifyStreamResponse(res) {
125
89
  const MAX_YIELD_CHARS = STREAM_RESPONSE_MAX_YIELD_CHARS;
126
90
  const MAX_BUFFER_CHARS = 256 * 1024;
127
91
  const body = res?.body ?? res;
@@ -351,7 +315,7 @@ const TOOL_ARG_ALIASES = {
351
315
  },
352
316
  };
353
317
  // Error types for better handling
354
- var ToolErrorType;
318
+ export var ToolErrorType;
355
319
  (function (ToolErrorType) {
356
320
  ToolErrorType["FILE_NOT_FOUND"] = "FILE_NOT_FOUND";
357
321
  ToolErrorType["PERMISSION_DENIED"] = "PERMISSION_DENIED";
@@ -360,8 +324,8 @@ var ToolErrorType;
360
324
  ToolErrorType["INVALID_ARGS"] = "INVALID_ARGS";
361
325
  ToolErrorType["EXECUTION_FAILED"] = "EXECUTION_FAILED";
362
326
  ToolErrorType["USER_CANCELLED"] = "USER_CANCELLED";
363
- })(ToolErrorType || (exports.ToolErrorType = ToolErrorType = {}));
364
- class AgenticTools {
327
+ })(ToolErrorType || (ToolErrorType = {}));
328
+ export class AgenticTools {
365
329
  logger;
366
330
  cwd;
367
331
  permissionCallback;
@@ -421,7 +385,7 @@ class AgenticTools {
421
385
  throw new Error(`Invalid external command for ${toolName} during ${operation}: command must be a non-empty string.`);
422
386
  }
423
387
  try {
424
- return (0, child_process_1.execSync)(command, options);
388
+ return execSync(command, options);
425
389
  }
426
390
  catch (error) {
427
391
  if (cleanup) {
@@ -609,7 +573,7 @@ class AgenticTools {
609
573
  fs.unlinkSync(lastOp.filePath);
610
574
  return {
611
575
  success: true,
612
- output: `${logger_js_1.CH.success} Undone: ${lastOp.description}\n File deleted: ${lastOp.filePath}`,
576
+ output: `${CH.success} Undone: ${lastOp.description}\n File deleted: ${lastOp.filePath}`,
613
577
  metadata: { remainingUndos: this.undoStack.length },
614
578
  };
615
579
  }
@@ -619,7 +583,7 @@ class AgenticTools {
619
583
  fs.writeFileSync(lastOp.filePath, lastOp.originalContent, 'utf-8');
620
584
  return {
621
585
  success: true,
622
- output: `${logger_js_1.CH.success} Undone: ${lastOp.description}\n File restored: ${lastOp.filePath}`,
586
+ output: `${CH.success} Undone: ${lastOp.description}\n File restored: ${lastOp.filePath}`,
623
587
  metadata: { remainingUndos: this.undoStack.length },
624
588
  };
625
589
  }
@@ -977,11 +941,45 @@ class AgenticTools {
977
941
  }
978
942
  return lastError || this.createErrorResult(ToolErrorType.EXECUTION_FAILED, 'Unknown error after retries');
979
943
  }
944
+ /**
945
+ * Tool names that mutate the user's filesystem, shell state, or remote
946
+ * services. Used by the dry-run / read-only gate below.
947
+ */
948
+ static MUTATING_TOOLS = new Set([
949
+ 'write_file', 'edit_file', 'multi_edit',
950
+ 'bash', 'ssh_exec',
951
+ 'git', 'repo',
952
+ ]);
953
+ /**
954
+ * `VIGTHORIA_DRY_RUN=1` and `VIGTHORIA_READ_ONLY=1` are end-user safety
955
+ * switches: every mutating tool short-circuits with a clear "would have
956
+ * happened" result instead of touching the filesystem or network.
957
+ *
958
+ * The flags are checked at call-time (not at construction time) so they
959
+ * can be flipped per-prompt by users who want to inspect agent intent
960
+ * before committing.
961
+ */
962
+ isDryRunActive() {
963
+ const flag = (name) => String(process.env[name] || '').trim().toLowerCase();
964
+ const isOn = (v) => v === '1' || v === 'true' || v === 'yes' || v === 'on';
965
+ return isOn(flag('VIGTHORIA_DRY_RUN')) || isOn(flag('VIGTHORIA_READ_ONLY'));
966
+ }
980
967
  /**
981
968
  * Execute the actual tool operation
982
969
  */
983
970
  async executeTool(call) {
984
971
  try {
972
+ if (this.isDryRunActive() && AgenticTools.MUTATING_TOOLS.has(call.tool)) {
973
+ const argSummary = this.safeStringifyArgs(call.args);
974
+ const message = `Dry-run: ${call.tool} would have run with ${argSummary}. Unset VIGTHORIA_DRY_RUN to execute.`;
975
+ this.logger.warn(message);
976
+ return {
977
+ success: true,
978
+ output: '',
979
+ dryRun: true,
980
+ message,
981
+ };
982
+ }
985
983
  switch (call.tool) {
986
984
  case 'read_file':
987
985
  return this.readFile(call.args);
@@ -1171,10 +1169,10 @@ class AgenticTools {
1171
1169
  */
1172
1170
  formatPermissionRequest(call, tool) {
1173
1171
  const riskColors = {
1174
- low: chalk_1.default.green,
1175
- medium: chalk_1.default.yellow,
1176
- high: chalk_1.default.red,
1177
- critical: chalk_1.default.bgRed.white,
1172
+ low: chalk.green,
1173
+ medium: chalk.yellow,
1174
+ high: chalk.red,
1175
+ critical: chalk.bgRed.white,
1178
1176
  };
1179
1177
  const riskIcons = {
1180
1178
  low: '🟢',
@@ -1184,41 +1182,41 @@ class AgenticTools {
1184
1182
  };
1185
1183
  const riskColor = riskColors[tool.riskLevel];
1186
1184
  const riskIcon = riskIcons[tool.riskLevel];
1187
- let msg = `\n${riskIcon} ${riskColor(`${tool.riskLevel.toUpperCase()} RISK`)} - AI wants to use ${chalk_1.default.cyan.bold(call.tool)}\n`;
1188
- msg += chalk_1.default.gray(logger_js_1.CH.hLine.repeat(50)) + '\n';
1185
+ let msg = `\n${riskIcon} ${riskColor(`${tool.riskLevel.toUpperCase()} RISK`)} - AI wants to use ${chalk.cyan.bold(call.tool)}\n`;
1186
+ msg += chalk.gray(CH.hLine.repeat(50)) + '\n';
1189
1187
  // Tool-specific details
1190
1188
  if (call.tool === 'bash') {
1191
- msg += `${chalk_1.default.gray(logger_js_1.CH.teeR + logger_js_1.CH.hLine)} ${chalk_1.default.white('Command:')} ${chalk_1.default.yellow(call.args.command)}\n`;
1189
+ msg += `${chalk.gray(CH.teeR + CH.hLine)} ${chalk.white('Command:')} ${chalk.yellow(call.args.command)}\n`;
1192
1190
  if (call.args.cwd) {
1193
- msg += `${chalk_1.default.gray(logger_js_1.CH.teeR + logger_js_1.CH.hLine)} ${chalk_1.default.white('Directory:')} ${call.args.cwd}\n`;
1191
+ msg += `${chalk.gray(CH.teeR + CH.hLine)} ${chalk.white('Directory:')} ${call.args.cwd}\n`;
1194
1192
  }
1195
- msg += `${chalk_1.default.gray(logger_js_1.CH.teeR + logger_js_1.CH.hLine)} ${chalk_1.default.white('Timeout:')} ${call.args.timeout || '30'}s\n`;
1193
+ msg += `${chalk.gray(CH.teeR + CH.hLine)} ${chalk.white('Timeout:')} ${call.args.timeout || '30'}s\n`;
1196
1194
  }
1197
1195
  else if (call.tool === 'write_file') {
1198
- msg += `${chalk_1.default.gray(logger_js_1.CH.teeR + logger_js_1.CH.hLine)} ${chalk_1.default.white('File:')} ${chalk_1.default.cyan(call.args.path)}\n`;
1196
+ msg += `${chalk.gray(CH.teeR + CH.hLine)} ${chalk.white('File:')} ${chalk.cyan(call.args.path)}\n`;
1199
1197
  const preview = call.args.content.substring(0, 100);
1200
- msg += `${chalk_1.default.gray(logger_js_1.CH.teeR + logger_js_1.CH.hLine)} ${chalk_1.default.white('Content preview:')} ${chalk_1.default.gray(preview)}${call.args.content.length > 100 ? '...' : ''}\n`;
1201
- msg += `${chalk_1.default.gray(logger_js_1.CH.teeR + logger_js_1.CH.hLine)} ${chalk_1.default.white('Size:')} ${call.args.content.length} bytes\n`;
1198
+ msg += `${chalk.gray(CH.teeR + CH.hLine)} ${chalk.white('Content preview:')} ${chalk.gray(preview)}${call.args.content.length > 100 ? '...' : ''}\n`;
1199
+ msg += `${chalk.gray(CH.teeR + CH.hLine)} ${chalk.white('Size:')} ${call.args.content.length} bytes\n`;
1202
1200
  }
1203
1201
  else if (call.tool === 'edit_file') {
1204
- msg += `${chalk_1.default.gray(logger_js_1.CH.teeR + logger_js_1.CH.hLine)} ${chalk_1.default.white('File:')} ${chalk_1.default.cyan(call.args.path)}\n`;
1205
- msg += `${chalk_1.default.gray(logger_js_1.CH.teeR + logger_js_1.CH.hLine)} ${chalk_1.default.white('Replace:')} ${chalk_1.default.red(call.args.old_text.substring(0, 50))}${call.args.old_text.length > 50 ? '...' : ''}\n`;
1206
- msg += `${chalk_1.default.gray(logger_js_1.CH.teeR + logger_js_1.CH.hLine)} ${chalk_1.default.white('With:')} ${chalk_1.default.green(call.args.new_text.substring(0, 50))}${call.args.new_text.length > 50 ? '...' : ''}\n`;
1202
+ msg += `${chalk.gray(CH.teeR + CH.hLine)} ${chalk.white('File:')} ${chalk.cyan(call.args.path)}\n`;
1203
+ msg += `${chalk.gray(CH.teeR + CH.hLine)} ${chalk.white('Replace:')} ${chalk.red(call.args.old_text.substring(0, 50))}${call.args.old_text.length > 50 ? '...' : ''}\n`;
1204
+ msg += `${chalk.gray(CH.teeR + CH.hLine)} ${chalk.white('With:')} ${chalk.green(call.args.new_text.substring(0, 50))}${call.args.new_text.length > 50 ? '...' : ''}\n`;
1207
1205
  }
1208
1206
  else if (call.tool === 'git') {
1209
- msg += `${chalk_1.default.gray(logger_js_1.CH.teeR + logger_js_1.CH.hLine)} ${chalk_1.default.white('Command:')} git ${chalk_1.default.yellow(call.args.args)}\n`;
1207
+ msg += `${chalk.gray(CH.teeR + CH.hLine)} ${chalk.white('Command:')} git ${chalk.yellow(call.args.args)}\n`;
1210
1208
  }
1211
1209
  // Safety info
1212
- msg += chalk_1.default.gray(logger_js_1.CH.hLine.repeat(50)) + '\n';
1210
+ msg += chalk.gray(CH.hLine.repeat(50)) + '\n';
1213
1211
  const canUndo = ['write_file', 'edit_file'].includes(call.tool);
1214
- msg += `${chalk_1.default.gray(logger_js_1.CH.teeR + logger_js_1.CH.hLine)} ${chalk_1.default.white('Undo:')} ${canUndo ? chalk_1.default.green(logger_js_1.CH.success + ' Available (use /undo)') : chalk_1.default.gray(logger_js_1.CH.error + ' Not available')}\n`;
1215
- msg += `${chalk_1.default.gray(logger_js_1.CH.bl + logger_js_1.CH.hLine)} ${chalk_1.default.white('Category:')} ${tool.category}\n`;
1212
+ msg += `${chalk.gray(CH.teeR + CH.hLine)} ${chalk.white('Undo:')} ${canUndo ? chalk.green(CH.success + ' Available (use /undo)') : chalk.gray(CH.error + ' Not available')}\n`;
1213
+ msg += `${chalk.gray(CH.bl + CH.hLine)} ${chalk.white('Category:')} ${tool.category}\n`;
1216
1214
  if (tool.dangerous) {
1217
- msg += `\n${chalk_1.default.red.bold(logger_js_1.CH.warnEmoji + ' WARNING: This is a potentially dangerous action!')}\n`;
1218
- msg += chalk_1.default.red(' The AI is requesting to execute commands on your system.\n');
1215
+ msg += `\n${chalk.red.bold(CH.warnEmoji + ' WARNING: This is a potentially dangerous action!')}\n`;
1216
+ msg += chalk.red(' The AI is requesting to execute commands on your system.\n');
1219
1217
  }
1220
1218
  // Add batch approval hint
1221
- msg += `\n${chalk_1.default.gray('Respond:')} ${chalk_1.default.white('[y]es')} ${chalk_1.default.gray('/')} ${chalk_1.default.white('[n]o')} ${chalk_1.default.gray('/')} ${chalk_1.default.cyan('[a]pprove all')} ${chalk_1.default.cyan(call.tool)} ${chalk_1.default.gray('for this turn')}\n`;
1219
+ msg += `\n${chalk.gray('Respond:')} ${chalk.white('[y]es')} ${chalk.gray('/')} ${chalk.white('[n]o')} ${chalk.gray('/')} ${chalk.cyan('[a]pprove all')} ${chalk.cyan(call.tool)} ${chalk.gray('for this turn')}\n`;
1222
1220
  return msg;
1223
1221
  }
1224
1222
  sleep(ms) {
@@ -1695,7 +1693,7 @@ class AgenticTools {
1695
1693
  grepWindows(args, searchPath) {
1696
1694
  // 1. Try ripgrep (rg) first — best cross-platform search tool
1697
1695
  try {
1698
- (0, child_process_1.execSync)('rg --version', { encoding: 'utf-8', timeout: 5000, stdio: 'pipe' });
1696
+ execSync('rg --version', { encoding: 'utf-8', timeout: 5000, stdio: 'pipe' });
1699
1697
  return this.grepWithRg(args, searchPath);
1700
1698
  }
1701
1699
  catch (error) {
@@ -1820,7 +1818,7 @@ class AgenticTools {
1820
1818
  const escapedPattern = args.pattern.replace(/'/g, "''");
1821
1819
  const cmd = `powershell -NoProfile -Command "Get-ChildItem -Path '${psPath}' -Recurse -File ${includeFilter} | Select-String -Pattern '${escapedPattern}' | ForEach-Object { $_.Path + ':' + $_.LineNumber + ':' + $_.Line }"`;
1822
1820
  try {
1823
- const output = (0, child_process_1.execSync)(cmd, {
1821
+ const output = execSync(cmd, {
1824
1822
  cwd: this.cwd,
1825
1823
  encoding: 'utf-8',
1826
1824
  maxBuffer: 5 * 1024 * 1024,
@@ -1977,7 +1975,7 @@ class AgenticTools {
1977
1975
  }
1978
1976
  git(args) {
1979
1977
  try {
1980
- const output = (0, child_process_1.execSync)(`git ${args.args}`, {
1978
+ const output = execSync(`git ${args.args}`, {
1981
1979
  cwd: this.cwd,
1982
1980
  encoding: 'utf-8',
1983
1981
  timeout: 60000,
@@ -2094,7 +2092,7 @@ class AgenticTools {
2094
2092
  // Try proxy first; direct Community server is only reachable when running on the
2095
2093
  // Vigthoria backend itself (isServerRuntime), never expose this fallback to remote users.
2096
2094
  const pushUrls = [`${apiBase}/api/community-repo/push`];
2097
- if ((0, api_js_1.isServerRuntime)()) {
2095
+ if (isServerRuntime()) {
2098
2096
  const directHost = ['local', 'host'].join('');
2099
2097
  pushUrls.push(`http://${directHost}:9000/api/repo/push`);
2100
2098
  }
@@ -2194,7 +2192,7 @@ class AgenticTools {
2194
2192
  suggestion: 'Available actions: push, pull, list, status, share, delete, clone'
2195
2193
  };
2196
2194
  }
2197
- const output = (0, child_process_1.execSync)(command, {
2195
+ const output = execSync(command, {
2198
2196
  cwd: this.cwd,
2199
2197
  encoding: 'utf-8',
2200
2198
  timeout: 120000,
@@ -2510,7 +2508,7 @@ class AgenticTools {
2510
2508
  sshCommand = `ssh -o BatchMode=yes -o StrictHostKeyChecking=accept-new -o ConnectTimeout=10 ${host} '${command.replace(/'/g, "'\\''")}'`;
2511
2509
  execOptions.shell = '/bin/sh';
2512
2510
  }
2513
- const output = (0, child_process_1.execSync)(sshCommand, execOptions);
2511
+ const output = execSync(sshCommand, execOptions);
2514
2512
  return {
2515
2513
  success: true,
2516
2514
  output: output.trim(),
@@ -2739,7 +2737,7 @@ class AgenticTools {
2739
2737
  }
2740
2738
  return {
2741
2739
  success: true,
2742
- output: `${logger_js_1.CH.success} Atomically edited ${applied.length} file(s):\n${applied.map(f => ` ✓ ${f}`).join('\n')}`,
2740
+ output: `${CH.success} Atomically edited ${applied.length} file(s):\n${applied.map(f => ` ✓ ${f}`).join('\n')}`,
2743
2741
  undoable: true,
2744
2742
  metadata: { filesEdited: applied.length, files: applied },
2745
2743
  };
@@ -2882,7 +2880,7 @@ class AgenticTools {
2882
2880
  rgArgs.push('--', query, this.cwd);
2883
2881
  const isWin = process.platform === 'win32';
2884
2882
  const quote = (s) => isWin ? `"${s}"` : `'${s}'`;
2885
- const rgOutput = (0, child_process_1.execSync)(`rg ${rgArgs.map(a => quote(a)).join(' ')}`, {
2883
+ const rgOutput = execSync(`rg ${rgArgs.map(a => quote(a)).join(' ')}`, {
2886
2884
  encoding: 'utf-8',
2887
2885
  timeout: 15000,
2888
2886
  maxBuffer: 5 * 1024 * 1024,
@@ -3450,4 +3448,3 @@ To use a tool, output a JSON block in a code fence with "tool" language:
3450
3448
  return prompt;
3451
3449
  }
3452
3450
  }
3453
- exports.AgenticTools = AgenticTools;
@@ -1,4 +1,3 @@
1
- "use strict";
2
1
  /**
3
2
  * Vigthoria CLI — Workspace Hash Cache
4
3
  *
@@ -7,24 +6,17 @@
7
6
  * - Changed/new files → sent first (highest budget priority)
8
7
  * - Unchanged files → sent last (trimmed by budget if token limit reached)
9
8
  */
10
- var __importDefault = (this && this.__importDefault) || function (mod) {
11
- return (mod && mod.__esModule) ? mod : { "default": mod };
12
- };
13
- Object.defineProperty(exports, "__esModule", { value: true });
14
- exports.getChangedFiles = getChangedFiles;
15
- exports.updateWorkspaceCache = updateWorkspaceCache;
16
- exports.summarizeChanges = summarizeChanges;
17
- const node_crypto_1 = require("node:crypto");
18
- const node_fs_1 = __importDefault(require("node:fs"));
19
- const node_path_1 = __importDefault(require("node:path"));
9
+ import { createHash } from 'node:crypto';
10
+ import fs from 'node:fs';
11
+ import path from 'node:path';
20
12
  const CACHE_SUBDIR = '.vigthoria';
21
13
  const CACHE_FILENAME = 'file-hashes.json';
22
14
  function getCachePath(workspacePath) {
23
- return node_path_1.default.join(workspacePath, CACHE_SUBDIR, CACHE_FILENAME);
15
+ return path.join(workspacePath, CACHE_SUBDIR, CACHE_FILENAME);
24
16
  }
25
17
  function hashFile(absPath) {
26
18
  try {
27
- return (0, node_crypto_1.createHash)('sha256').update(node_fs_1.default.readFileSync(absPath)).digest('hex');
19
+ return createHash('sha256').update(fs.readFileSync(absPath)).digest('hex');
28
20
  }
29
21
  catch {
30
22
  return '';
@@ -32,7 +24,7 @@ function hashFile(absPath) {
32
24
  }
33
25
  function loadCache(workspacePath) {
34
26
  try {
35
- return JSON.parse(node_fs_1.default.readFileSync(getCachePath(workspacePath), 'utf-8'));
27
+ return JSON.parse(fs.readFileSync(getCachePath(workspacePath), 'utf-8'));
36
28
  }
37
29
  catch {
38
30
  return {};
@@ -40,10 +32,10 @@ function loadCache(workspacePath) {
40
32
  }
41
33
  function persistCache(workspacePath, hashes) {
42
34
  try {
43
- const cacheDir = node_path_1.default.join(workspacePath, CACHE_SUBDIR);
44
- if (!node_fs_1.default.existsSync(cacheDir))
45
- node_fs_1.default.mkdirSync(cacheDir, { recursive: true });
46
- node_fs_1.default.writeFileSync(getCachePath(workspacePath), JSON.stringify(hashes, null, 2), 'utf-8');
35
+ const cacheDir = path.join(workspacePath, CACHE_SUBDIR);
36
+ if (!fs.existsSync(cacheDir))
37
+ fs.mkdirSync(cacheDir, { recursive: true });
38
+ fs.writeFileSync(getCachePath(workspacePath), JSON.stringify(hashes, null, 2), 'utf-8');
47
39
  }
48
40
  catch { /* non-fatal */ }
49
41
  }
@@ -53,13 +45,13 @@ function persistCache(workspacePath, hashes) {
53
45
  * @param workspacePath Absolute project root.
54
46
  * @param relativePaths Workspace-relative (or absolute) file paths to check.
55
47
  */
56
- function getChangedFiles(workspacePath, relativePaths) {
48
+ export function getChangedFiles(workspacePath, relativePaths) {
57
49
  const cache = loadCache(workspacePath);
58
50
  const changed = [];
59
51
  const unchanged = [];
60
52
  for (const rel of relativePaths) {
61
- const abs = node_path_1.default.isAbsolute(rel) ? rel : node_path_1.default.join(workspacePath, rel);
62
- const key = node_path_1.default.relative(workspacePath, abs).replace(/\\/g, '/');
53
+ const abs = path.isAbsolute(rel) ? rel : path.join(workspacePath, rel);
54
+ const key = path.relative(workspacePath, abs).replace(/\\/g, '/');
63
55
  const currentHash = hashFile(abs);
64
56
  if (!currentHash || cache[key] !== currentHash) {
65
57
  changed.push(rel);
@@ -74,13 +66,13 @@ function getChangedFiles(workspacePath, relativePaths) {
74
66
  * Write current hashes for the given files into the persistent cache.
75
67
  * Call this after an agent run completes successfully.
76
68
  */
77
- function updateWorkspaceCache(workspacePath, relativePaths) {
78
- if (!workspacePath || !node_fs_1.default.existsSync(workspacePath))
69
+ export function updateWorkspaceCache(workspacePath, relativePaths) {
70
+ if (!workspacePath || !fs.existsSync(workspacePath))
79
71
  return;
80
72
  const cache = loadCache(workspacePath);
81
73
  for (const rel of relativePaths) {
82
- const abs = node_path_1.default.isAbsolute(rel) ? rel : node_path_1.default.join(workspacePath, rel);
83
- const key = node_path_1.default.relative(workspacePath, abs).replace(/\\/g, '/');
74
+ const abs = path.isAbsolute(rel) ? rel : path.join(workspacePath, rel);
75
+ const key = path.relative(workspacePath, abs).replace(/\\/g, '/');
84
76
  const hash = hashFile(abs);
85
77
  if (hash)
86
78
  cache[key] = hash;
@@ -90,7 +82,7 @@ function updateWorkspaceCache(workspacePath, relativePaths) {
90
82
  /**
91
83
  * Return a human-readable summary of changes since last cache update.
92
84
  */
93
- function summarizeChanges(workspacePath, relativePaths) {
85
+ export function summarizeChanges(workspacePath, relativePaths) {
94
86
  const { changed, unchanged, total } = getChangedFiles(workspacePath, relativePaths);
95
87
  return `${changed.length} changed, ${unchanged.length} unchanged of ${total} files tracked`;
96
88
  }