vigthoria-cli 1.8.19 → 1.9.5
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/README.md +16 -10
- package/dist/commands/auth.d.ts +36 -18
- package/dist/commands/auth.js +440 -329
- package/dist/commands/chat.d.ts +12 -0
- package/dist/commands/chat.js +287 -48
- package/dist/commands/config.d.ts +2 -0
- package/dist/commands/config.js +40 -20
- package/dist/commands/index.d.ts +12 -0
- package/dist/commands/index.js +182 -0
- package/dist/commands/legion.d.ts +49 -7
- package/dist/commands/legion.js +1418 -72
- package/dist/commands/preview.js +32 -7
- package/dist/commands/repo.js +19 -13
- package/dist/commands/update.d.ts +9 -0
- package/dist/commands/update.js +235 -0
- package/dist/index.d.ts +4 -1
- package/dist/index.js +472 -51
- package/dist/utils/api.d.ts +24 -9
- package/dist/utils/api.js +720 -159
- package/dist/utils/config.js +9 -10
- package/dist/utils/context-ranker.d.ts +24 -0
- package/dist/utils/context-ranker.js +147 -0
- package/dist/utils/post-write-validator.d.ts +25 -0
- package/dist/utils/post-write-validator.js +138 -0
- package/dist/utils/session.d.ts +19 -0
- package/dist/utils/session.js +91 -6
- package/dist/utils/task-display.d.ts +31 -0
- package/dist/utils/task-display.js +115 -0
- package/dist/utils/tools.d.ts +26 -0
- package/dist/utils/tools.js +563 -58
- package/dist/utils/workspace-cache.d.ts +31 -0
- package/dist/utils/workspace-cache.js +96 -0
- package/package.json +13 -3
package/dist/commands/preview.js
CHANGED
|
@@ -254,14 +254,36 @@ class PreviewCommand {
|
|
|
254
254
|
* Open URL in default browser
|
|
255
255
|
*/
|
|
256
256
|
openBrowser(url) {
|
|
257
|
-
const {
|
|
257
|
+
const { execFile } = require('child_process');
|
|
258
258
|
const platform = process.platform;
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
259
|
+
// Validate URL scheme before passing to OS — prevents shell injection via crafted URLs
|
|
260
|
+
try {
|
|
261
|
+
const parsed = new URL(url);
|
|
262
|
+
if (parsed.protocol !== 'https:' && parsed.protocol !== 'http:')
|
|
263
|
+
return;
|
|
264
|
+
const safeUrl = parsed.href;
|
|
265
|
+
if (platform === 'darwin') {
|
|
266
|
+
execFile('open', [safeUrl], (err) => {
|
|
267
|
+
if (err)
|
|
268
|
+
this.logger.debug(`Could not auto-open browser: ${err.message}`);
|
|
269
|
+
});
|
|
263
270
|
}
|
|
264
|
-
|
|
271
|
+
else if (platform === 'win32') {
|
|
272
|
+
execFile('cmd', ['/c', 'start', '', safeUrl], (err) => {
|
|
273
|
+
if (err)
|
|
274
|
+
this.logger.debug(`Could not auto-open browser: ${err.message}`);
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
else {
|
|
278
|
+
execFile('xdg-open', [safeUrl], (err) => {
|
|
279
|
+
if (err)
|
|
280
|
+
this.logger.debug(`Could not auto-open browser: ${err.message}`);
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
catch {
|
|
285
|
+
this.logger.debug(`Skipping browser open — invalid URL: ${url}`);
|
|
286
|
+
}
|
|
265
287
|
}
|
|
266
288
|
/**
|
|
267
289
|
* Show consolidated diff of recent agent changes using git
|
|
@@ -322,7 +344,10 @@ class PreviewCommand {
|
|
|
322
344
|
let oldContent = '';
|
|
323
345
|
if (modified.includes(relPath)) {
|
|
324
346
|
try {
|
|
325
|
-
|
|
347
|
+
// Validate relPath is a safe relative path before interpolating — prevents injection
|
|
348
|
+
if (/^[a-zA-Z0-9_\-./]+$/.test(relPath) && !relPath.includes('..')) {
|
|
349
|
+
oldContent = execSync(`git show HEAD:${relPath}`, { cwd: projectPath, encoding: 'utf-8' });
|
|
350
|
+
}
|
|
326
351
|
}
|
|
327
352
|
catch {
|
|
328
353
|
// File is new or not tracked
|
package/dist/commands/repo.js
CHANGED
|
@@ -460,17 +460,17 @@ class RepoCommand {
|
|
|
460
460
|
const os = require('os');
|
|
461
461
|
const platform = os.platform();
|
|
462
462
|
if (platform === 'win32') {
|
|
463
|
-
// Use PowerShell's Expand-Archive
|
|
464
|
-
const {
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
});
|
|
463
|
+
// Use PowerShell's Expand-Archive — args as array to prevent injection
|
|
464
|
+
const { execFileSync } = await import('child_process');
|
|
465
|
+
execFileSync('powershell', [
|
|
466
|
+
'-NoProfile', '-NonInteractive', '-Command',
|
|
467
|
+
`Expand-Archive -Path '${tempArchive.replace(/'/g, "''")}' -DestinationPath '${outputPath.replace(/'/g, "''")}' -Force`
|
|
468
|
+
], { stdio: 'ignore', windowsHide: true });
|
|
469
469
|
}
|
|
470
470
|
else {
|
|
471
|
-
// Use unzip on Unix-like systems
|
|
472
|
-
const {
|
|
473
|
-
|
|
471
|
+
// Use unzip on Unix-like systems — args as array to prevent injection
|
|
472
|
+
const { execFileSync } = await import('child_process');
|
|
473
|
+
execFileSync('unzip', ['-o', tempArchive, '-d', outputPath], { stdio: 'ignore' });
|
|
474
474
|
}
|
|
475
475
|
fs.unlinkSync(tempArchive);
|
|
476
476
|
}
|
|
@@ -750,14 +750,20 @@ class RepoCommand {
|
|
|
750
750
|
console.log(chalk_1.default.bold(` ${data.url}\n`));
|
|
751
751
|
if (options.browser) {
|
|
752
752
|
try {
|
|
753
|
-
const {
|
|
753
|
+
const { execFileSync } = await import('child_process');
|
|
754
754
|
const platform = process.platform;
|
|
755
|
+
// Validate URL scheme before passing to OS — prevents shell injection
|
|
756
|
+
const parsedUrl = new URL(data.url);
|
|
757
|
+
if (parsedUrl.protocol !== 'https:' && parsedUrl.protocol !== 'http:') {
|
|
758
|
+
throw new Error('Unsafe URL scheme for browser open');
|
|
759
|
+
}
|
|
760
|
+
const safeUrl = parsedUrl.href;
|
|
755
761
|
if (platform === 'win32')
|
|
756
|
-
|
|
762
|
+
execFileSync('cmd', ['/c', 'start', '', safeUrl], { stdio: 'ignore', windowsHide: true });
|
|
757
763
|
else if (platform === 'darwin')
|
|
758
|
-
|
|
764
|
+
execFileSync('open', [safeUrl], { stdio: 'ignore' });
|
|
759
765
|
else
|
|
760
|
-
|
|
766
|
+
execFileSync('xdg-open', [safeUrl], { stdio: 'ignore' });
|
|
761
767
|
}
|
|
762
768
|
catch { /* browser open is optional */ }
|
|
763
769
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
type PackageManager = 'npm' | 'pnpm' | 'yarn' | 'bun';
|
|
2
|
+
interface UpdateOptions {
|
|
3
|
+
check?: boolean;
|
|
4
|
+
packageManager?: PackageManager;
|
|
5
|
+
global?: boolean;
|
|
6
|
+
}
|
|
7
|
+
export declare function updateCommand(options?: UpdateOptions): Promise<void>;
|
|
8
|
+
export declare function update(): Promise<void>;
|
|
9
|
+
export default updateCommand;
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.updateCommand = updateCommand;
|
|
37
|
+
exports.update = update;
|
|
38
|
+
const node_child_process_1 = require("node:child_process");
|
|
39
|
+
const node_fs_1 = require("node:fs");
|
|
40
|
+
const path = __importStar(require("node:path"));
|
|
41
|
+
const node_util_1 = require("node:util");
|
|
42
|
+
const tools_js_1 = require("../utils/tools.js");
|
|
43
|
+
const execFileAsync = (0, node_util_1.promisify)(node_child_process_1.execFile);
|
|
44
|
+
function markSuccessExit() {
|
|
45
|
+
process.exitCode = 0;
|
|
46
|
+
}
|
|
47
|
+
function markErrorExit() {
|
|
48
|
+
process.exitCode = 1;
|
|
49
|
+
}
|
|
50
|
+
function findPackageJson(startDir) {
|
|
51
|
+
let currentDir = startDir;
|
|
52
|
+
for (let depth = 0; depth < 8; depth += 1) {
|
|
53
|
+
const candidate = path.join(currentDir, 'package.json');
|
|
54
|
+
if ((0, node_fs_1.existsSync)(candidate)) {
|
|
55
|
+
return candidate;
|
|
56
|
+
}
|
|
57
|
+
const parentDir = path.join(currentDir, '..');
|
|
58
|
+
if (parentDir === currentDir) {
|
|
59
|
+
break;
|
|
60
|
+
}
|
|
61
|
+
currentDir = parentDir;
|
|
62
|
+
}
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
function readOwnPackageJson() {
|
|
66
|
+
const currentFile = __filename;
|
|
67
|
+
const packagePath = findPackageJson(path.join(currentFile, '..'));
|
|
68
|
+
if (!packagePath) {
|
|
69
|
+
throw new Error('Unable to locate package.json for the Vigthoria CLI.');
|
|
70
|
+
}
|
|
71
|
+
try {
|
|
72
|
+
return JSON.parse((0, node_fs_1.readFileSync)(packagePath, 'utf8'));
|
|
73
|
+
}
|
|
74
|
+
catch (error) {
|
|
75
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
76
|
+
throw new Error(`Unable to read package metadata: ${message}`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
function compareVersions(a, b) {
|
|
80
|
+
const parse = (version) => version.replace(/^v/, '').split(/[.-]/).map((part) => {
|
|
81
|
+
const value = Number.parseInt(part, 10);
|
|
82
|
+
return Number.isNaN(value) ? 0 : value;
|
|
83
|
+
});
|
|
84
|
+
const left = parse(a);
|
|
85
|
+
const right = parse(b);
|
|
86
|
+
const length = Math.max(left.length, right.length);
|
|
87
|
+
for (let index = 0; index < length; index += 1) {
|
|
88
|
+
const leftValue = left[index] ?? 0;
|
|
89
|
+
const rightValue = right[index] ?? 0;
|
|
90
|
+
if (leftValue > rightValue)
|
|
91
|
+
return 1;
|
|
92
|
+
if (leftValue < rightValue)
|
|
93
|
+
return -1;
|
|
94
|
+
}
|
|
95
|
+
return 0;
|
|
96
|
+
}
|
|
97
|
+
function quoteCmdArg(value) {
|
|
98
|
+
if (!/[\s"&()<>^|]/.test(value)) {
|
|
99
|
+
return value;
|
|
100
|
+
}
|
|
101
|
+
return `"${value.replace(/(\\*)"/g, '$1$1\\"')}"`;
|
|
102
|
+
}
|
|
103
|
+
function toPlatformCommand(command, args) {
|
|
104
|
+
if (process.platform !== 'win32') {
|
|
105
|
+
return { command, args };
|
|
106
|
+
}
|
|
107
|
+
const cmdPath = process.env.ComSpec || path.join(process.env.SystemRoot || 'C:\\Windows', 'System32', 'cmd.exe');
|
|
108
|
+
return {
|
|
109
|
+
command: cmdPath,
|
|
110
|
+
args: ['/d', '/s', '/c', [command, ...args].map(quoteCmdArg).join(' ')],
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
async function execPackageManager(command, args, timeout) {
|
|
114
|
+
const platformCommand = toPlatformCommand(command, args);
|
|
115
|
+
const { stdout } = await execFileAsync(platformCommand.command, platformCommand.args, {
|
|
116
|
+
timeout,
|
|
117
|
+
maxBuffer: 1024 * 1024,
|
|
118
|
+
windowsHide: true,
|
|
119
|
+
});
|
|
120
|
+
return stdout;
|
|
121
|
+
}
|
|
122
|
+
async function getLatestVersion(packageName) {
|
|
123
|
+
try {
|
|
124
|
+
const stdout = await execPackageManager('npm', ['view', packageName, 'version'], 30_000);
|
|
125
|
+
const latest = stdout.trim();
|
|
126
|
+
if (!latest) {
|
|
127
|
+
throw new Error('npm returned an empty version response');
|
|
128
|
+
}
|
|
129
|
+
return latest;
|
|
130
|
+
}
|
|
131
|
+
catch (error) {
|
|
132
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
133
|
+
throw new Error(`Unable to check the latest published version: ${message}`);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
async function getVersionInfo() {
|
|
137
|
+
const packageJson = readOwnPackageJson();
|
|
138
|
+
const packageName = packageJson.name;
|
|
139
|
+
const current = packageJson.version;
|
|
140
|
+
if (!packageName || !current) {
|
|
141
|
+
throw new Error('The CLI package metadata must include both name and version.');
|
|
142
|
+
}
|
|
143
|
+
const latest = await getLatestVersion(packageName);
|
|
144
|
+
return {
|
|
145
|
+
current,
|
|
146
|
+
latest,
|
|
147
|
+
packageName,
|
|
148
|
+
updateAvailable: compareVersions(current, latest) < 0,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
function resolveInstallCommand(packageManager, packageName, installGlobal) {
|
|
152
|
+
const target = `${packageName}@latest`;
|
|
153
|
+
switch (packageManager) {
|
|
154
|
+
case 'pnpm':
|
|
155
|
+
return { command: 'pnpm', args: installGlobal ? ['add', '--global', target] : ['add', '-D', target] };
|
|
156
|
+
case 'yarn':
|
|
157
|
+
return { command: 'yarn', args: installGlobal ? ['global', 'add', target] : ['add', '--dev', target] };
|
|
158
|
+
case 'bun':
|
|
159
|
+
return { command: 'bun', args: installGlobal ? ['add', '--global', target] : ['add', '--dev', target] };
|
|
160
|
+
case 'npm':
|
|
161
|
+
default:
|
|
162
|
+
return { command: 'npm', args: installGlobal ? ['install', '--global', target] : ['install', '--save-dev', target] };
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
function formatCommand(command) {
|
|
166
|
+
return [command.command, ...command.args].map(quoteCmdArg).join(' ');
|
|
167
|
+
}
|
|
168
|
+
async function runInstall(packageManager, packageName, installGlobal) {
|
|
169
|
+
const installCommand = resolveInstallCommand(packageManager, packageName, installGlobal);
|
|
170
|
+
await execPackageManager(installCommand.command, installCommand.args, 120_000);
|
|
171
|
+
}
|
|
172
|
+
async function updateCommand(options = {}) {
|
|
173
|
+
try {
|
|
174
|
+
const info = await getVersionInfo();
|
|
175
|
+
console.log(`Vigthoria CLI current version: ${info.current}`);
|
|
176
|
+
console.log(`Vigthoria CLI latest version: ${info.latest}`);
|
|
177
|
+
if (!info.updateAvailable) {
|
|
178
|
+
console.log('You are already running the latest Vigthoria CLI.');
|
|
179
|
+
markSuccessExit();
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
console.log(`Update available for ${info.packageName}: ${info.current} → ${info.latest}`);
|
|
183
|
+
if (options.check) {
|
|
184
|
+
markSuccessExit();
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
const packageManager = options.packageManager ?? 'npm';
|
|
188
|
+
const installGlobal = options.global ?? true;
|
|
189
|
+
console.log(`Installing ${info.packageName}@latest with ${packageManager}...`);
|
|
190
|
+
if (process.platform === 'win32') {
|
|
191
|
+
const installerResult = await (0, tools_js_1.installUpdateWindows)();
|
|
192
|
+
if (!installerResult.success && installerResult.error === 'ENOENT') {
|
|
193
|
+
const fallbackCommand = resolveInstallCommand(packageManager, info.packageName, installGlobal);
|
|
194
|
+
console.warn('Windows update installer was not found (ENOENT).');
|
|
195
|
+
console.warn('The bundled Windows installer may be missing from this installation.');
|
|
196
|
+
console.warn(`Manual installation command: ${formatCommand(fallbackCommand)}`);
|
|
197
|
+
console.warn('If automatic fallback fails, run the command above manually or download the latest Windows installer from the Vigthoria release page.');
|
|
198
|
+
await execPackageManager(fallbackCommand.command, fallbackCommand.args, 120_000);
|
|
199
|
+
console.log('Package manager installation finished successfully.');
|
|
200
|
+
}
|
|
201
|
+
else if (!installerResult.success) {
|
|
202
|
+
throw new Error(installerResult.error || 'Windows installer failed to start.');
|
|
203
|
+
}
|
|
204
|
+
else {
|
|
205
|
+
console.log('Windows installer started successfully. Complete the installer prompts to finish updating.');
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
else {
|
|
209
|
+
await runInstall(packageManager, info.packageName, installGlobal);
|
|
210
|
+
console.log('Package manager installation finished successfully.');
|
|
211
|
+
}
|
|
212
|
+
console.log('Vigthoria CLI update complete.');
|
|
213
|
+
markSuccessExit();
|
|
214
|
+
}
|
|
215
|
+
catch (error) {
|
|
216
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
217
|
+
console.error(`Update failed: ${message}`);
|
|
218
|
+
markErrorExit();
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
async function update() {
|
|
222
|
+
try {
|
|
223
|
+
await updateCommand();
|
|
224
|
+
if (process.exitCode === 1) {
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
markSuccessExit();
|
|
228
|
+
}
|
|
229
|
+
catch (error) {
|
|
230
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
231
|
+
console.error(`Update failed: ${message}`);
|
|
232
|
+
markErrorExit();
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
exports.default = updateCommand;
|
package/dist/index.d.ts
CHANGED
|
@@ -15,4 +15,7 @@
|
|
|
15
15
|
* vigthoria workflow - Manage repeatable VigFlow workflows
|
|
16
16
|
* vigthoria operator - Start BMAD operator mode
|
|
17
17
|
*/
|
|
18
|
-
export
|
|
18
|
+
export declare function validateReleaseMetadata(): boolean;
|
|
19
|
+
export declare function setupErrorHandlers(): void;
|
|
20
|
+
export declare function main(args: string[]): Promise<void>;
|
|
21
|
+
export declare const __cliErrorHandlingReady = true;
|