vigthoria-cli 1.10.37 → 1.10.47
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/agent-session-menu.d.ts +19 -0
- package/dist/commands/agent-session-menu.js +155 -0
- package/dist/commands/auth.js +68 -51
- package/dist/commands/bridge.js +19 -12
- package/dist/commands/cancel.js +22 -15
- package/dist/commands/chat.d.ts +0 -28
- package/dist/commands/chat.js +407 -1254
- package/dist/commands/config.js +73 -33
- package/dist/commands/deploy.js +123 -83
- package/dist/commands/device.js +61 -21
- package/dist/commands/edit.js +39 -32
- package/dist/commands/explain.js +25 -18
- package/dist/commands/generate.js +44 -37
- package/dist/commands/hub.js +102 -95
- package/dist/commands/index.js +46 -41
- package/dist/commands/legion.js +186 -146
- package/dist/commands/review.js +36 -29
- package/dist/commands/security.js +12 -5
- package/dist/commands/wallet.js +35 -28
- package/dist/commands/workflow.js +20 -13
- package/dist/utils/brain-hub-client.js +5 -1
- package/dist/utils/bridge-client.js +52 -11
- package/dist/utils/codebase-indexer.js +41 -4
- package/dist/utils/context-ranker.js +21 -15
- package/dist/utils/files.js +42 -5
- package/dist/utils/logger.js +50 -42
- package/dist/utils/persona.js +8 -3
- package/dist/utils/post-write-validator.js +29 -22
- package/dist/utils/project-memory.js +23 -16
- package/dist/utils/task-display.js +20 -13
- package/dist/utils/workspace-brain-service.js +45 -8
- package/dist/utils/workspace-cache.js +26 -18
- package/dist/utils/workspace-stream.js +63 -21
- package/package.json +3 -6
- package/dist/commands/fork.d.ts +0 -17
- package/dist/commands/fork.js +0 -164
- package/dist/commands/history.d.ts +0 -17
- package/dist/commands/history.js +0 -113
- package/dist/commands/preview.d.ts +0 -55
- package/dist/commands/preview.js +0 -467
- package/dist/commands/replay.d.ts +0 -18
- package/dist/commands/replay.js +0 -156
- package/dist/commands/repo.d.ts +0 -97
- package/dist/commands/repo.js +0 -773
- package/dist/commands/update.d.ts +0 -9
- package/dist/commands/update.js +0 -201
- package/dist/index.d.ts +0 -21
- package/dist/index.js +0 -1823
- package/dist/utils/api.d.ts +0 -572
- package/dist/utils/api.js +0 -6548
- package/dist/utils/cli-state.d.ts +0 -54
- package/dist/utils/cli-state.js +0 -185
- package/dist/utils/config.d.ts +0 -85
- package/dist/utils/config.js +0 -267
- package/dist/utils/session.d.ts +0 -118
- package/dist/utils/session.js +0 -423
- package/dist/utils/tools.d.ts +0 -276
- package/dist/utils/tools.js +0 -3516
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
"use strict";
|
|
1
2
|
/**
|
|
2
3
|
* Vigthoria CLI — Semantic Context Ranker
|
|
3
4
|
*
|
|
@@ -7,8 +8,13 @@
|
|
|
7
8
|
*
|
|
8
9
|
* No external dependencies — uses only Node.js built-ins.
|
|
9
10
|
*/
|
|
10
|
-
|
|
11
|
-
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.buildSemanticContext = buildSemanticContext;
|
|
16
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
17
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
12
18
|
const IGNORED_DIRS = new Set([
|
|
13
19
|
'.git', 'node_modules', 'dist', '.next', '__pycache__',
|
|
14
20
|
'.vigthoria', 'coverage', '.cache', '.turbo', 'build', 'out',
|
|
@@ -39,8 +45,8 @@ function extractKeywords(prompt) {
|
|
|
39
45
|
function scoreFile(filePath, keywords) {
|
|
40
46
|
if (keywords.length === 0)
|
|
41
47
|
return 0;
|
|
42
|
-
const filename =
|
|
43
|
-
const parentDir =
|
|
48
|
+
const filename = node_path_1.default.basename(filePath).toLowerCase();
|
|
49
|
+
const parentDir = node_path_1.default.basename(node_path_1.default.dirname(filePath)).toLowerCase();
|
|
44
50
|
let score = 0;
|
|
45
51
|
for (const kw of keywords) {
|
|
46
52
|
// Filename match (high weight)
|
|
@@ -51,7 +57,7 @@ function scoreFile(filePath, keywords) {
|
|
|
51
57
|
score += 6;
|
|
52
58
|
}
|
|
53
59
|
try {
|
|
54
|
-
const content =
|
|
60
|
+
const content = node_fs_1.default.readFileSync(filePath, 'utf-8').slice(0, 300000);
|
|
55
61
|
const lower = content.toLowerCase();
|
|
56
62
|
for (const kw of keywords) {
|
|
57
63
|
const escaped = kw.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
@@ -67,14 +73,14 @@ function scoreFile(filePath, keywords) {
|
|
|
67
73
|
function walkWorkspace(dir, maxFiles = 800) {
|
|
68
74
|
const results = [];
|
|
69
75
|
const stack = [dir];
|
|
70
|
-
const workspaceRoot =
|
|
76
|
+
const workspaceRoot = node_path_1.default.resolve(dir);
|
|
71
77
|
while (stack.length > 0 && results.length < maxFiles) {
|
|
72
78
|
const current = stack.pop();
|
|
73
79
|
if (!current)
|
|
74
80
|
continue;
|
|
75
81
|
let entries;
|
|
76
82
|
try {
|
|
77
|
-
entries =
|
|
83
|
+
entries = node_fs_1.default.readdirSync(current, { withFileTypes: true });
|
|
78
84
|
}
|
|
79
85
|
catch {
|
|
80
86
|
continue;
|
|
@@ -85,12 +91,12 @@ function walkWorkspace(dir, maxFiles = 800) {
|
|
|
85
91
|
break;
|
|
86
92
|
if (IGNORED_DIRS.has(entry.name))
|
|
87
93
|
continue;
|
|
88
|
-
const fullPath =
|
|
94
|
+
const fullPath = node_path_1.default.join(current, entry.name);
|
|
89
95
|
// Security: skip symlinks that escape workspace root (fixes 8.2)
|
|
90
96
|
if (entry.isSymbolicLink()) {
|
|
91
97
|
try {
|
|
92
|
-
const real =
|
|
93
|
-
if (!real.startsWith(workspaceRoot +
|
|
98
|
+
const real = node_fs_1.default.realpathSync(fullPath);
|
|
99
|
+
if (!real.startsWith(workspaceRoot + node_path_1.default.sep) && real !== workspaceRoot)
|
|
94
100
|
continue;
|
|
95
101
|
}
|
|
96
102
|
catch {
|
|
@@ -100,7 +106,7 @@ function walkWorkspace(dir, maxFiles = 800) {
|
|
|
100
106
|
if (entry.isDirectory()) {
|
|
101
107
|
stack.push(fullPath);
|
|
102
108
|
}
|
|
103
|
-
else if (entry.isFile() && TEXT_EXTENSIONS.has(
|
|
109
|
+
else if (entry.isFile() && TEXT_EXTENSIONS.has(node_path_1.default.extname(entry.name).toLowerCase())) {
|
|
104
110
|
results.push(fullPath);
|
|
105
111
|
}
|
|
106
112
|
}
|
|
@@ -111,8 +117,8 @@ function walkWorkspace(dir, maxFiles = 800) {
|
|
|
111
117
|
* Score and rank workspace files by relevance to the given prompt.
|
|
112
118
|
* Returns the top N files with path, score, and content snippet.
|
|
113
119
|
*/
|
|
114
|
-
|
|
115
|
-
if (!workspacePath || !
|
|
120
|
+
function buildSemanticContext(workspacePath, prompt, topN = 12) {
|
|
121
|
+
if (!workspacePath || !node_fs_1.default.existsSync(workspacePath)) {
|
|
116
122
|
return { topFiles: [], totalFilesScanned: 0, keywords: [] };
|
|
117
123
|
}
|
|
118
124
|
const keywords = extractKeywords(prompt);
|
|
@@ -128,11 +134,11 @@ export function buildSemanticContext(workspacePath, prompt, topN = 12) {
|
|
|
128
134
|
const topFiles = scored.map(({ filePath, score }) => {
|
|
129
135
|
let snippet = '';
|
|
130
136
|
try {
|
|
131
|
-
snippet =
|
|
137
|
+
snippet = node_fs_1.default.readFileSync(filePath, 'utf-8').slice(0, 600);
|
|
132
138
|
}
|
|
133
139
|
catch { /* ignore */ }
|
|
134
140
|
return {
|
|
135
|
-
path:
|
|
141
|
+
path: node_path_1.default.relative(workspacePath, filePath).replace(/\\/g, '/'),
|
|
136
142
|
score,
|
|
137
143
|
snippet,
|
|
138
144
|
};
|
package/dist/utils/files.js
CHANGED
|
@@ -1,10 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
1
2
|
/**
|
|
2
3
|
* File utilities for Vigthoria CLI
|
|
3
4
|
*/
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
6
|
+
if (k2 === undefined) k2 = k;
|
|
7
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
8
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
9
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
10
|
+
}
|
|
11
|
+
Object.defineProperty(o, k2, desc);
|
|
12
|
+
}) : (function(o, m, k, k2) {
|
|
13
|
+
if (k2 === undefined) k2 = k;
|
|
14
|
+
o[k2] = m[k];
|
|
15
|
+
}));
|
|
16
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
17
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
18
|
+
}) : function(o, v) {
|
|
19
|
+
o["default"] = v;
|
|
20
|
+
});
|
|
21
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
22
|
+
var ownKeys = function(o) {
|
|
23
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
24
|
+
var ar = [];
|
|
25
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
26
|
+
return ar;
|
|
27
|
+
};
|
|
28
|
+
return ownKeys(o);
|
|
29
|
+
};
|
|
30
|
+
return function (mod) {
|
|
31
|
+
if (mod && mod.__esModule) return mod;
|
|
32
|
+
var result = {};
|
|
33
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
34
|
+
__setModuleDefault(result, mod);
|
|
35
|
+
return result;
|
|
36
|
+
};
|
|
37
|
+
})();
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.FileUtils = void 0;
|
|
40
|
+
const fs = __importStar(require("fs"));
|
|
41
|
+
const path = __importStar(require("path"));
|
|
42
|
+
const glob_1 = require("glob");
|
|
43
|
+
class FileUtils {
|
|
8
44
|
projectRoot;
|
|
9
45
|
ignorePatterns;
|
|
10
46
|
constructor(projectRoot, ignorePatterns = []) {
|
|
@@ -94,7 +130,7 @@ export class FileUtils {
|
|
|
94
130
|
if (!fs.existsSync(this.projectRoot)) {
|
|
95
131
|
return [];
|
|
96
132
|
}
|
|
97
|
-
const files = await glob(pattern, {
|
|
133
|
+
const files = await (0, glob_1.glob)(pattern, {
|
|
98
134
|
cwd: this.projectRoot,
|
|
99
135
|
ignore: this.ignorePatterns,
|
|
100
136
|
nodir: true,
|
|
@@ -239,3 +275,4 @@ export class FileUtils {
|
|
|
239
275
|
return { added, removed };
|
|
240
276
|
}
|
|
241
277
|
}
|
|
278
|
+
exports.FileUtils = FileUtils;
|
package/dist/utils/logger.js
CHANGED
|
@@ -1,8 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
1
2
|
/**
|
|
2
3
|
* Logger utility for Vigthoria CLI
|
|
3
4
|
*/
|
|
4
|
-
|
|
5
|
-
|
|
5
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
6
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
7
|
+
};
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.Logger = exports.CH = void 0;
|
|
10
|
+
exports.createSpinner = createSpinner;
|
|
11
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
12
|
+
const ora_1 = __importDefault(require("ora"));
|
|
6
13
|
/**
|
|
7
14
|
* Platform-aware character map.
|
|
8
15
|
*
|
|
@@ -14,7 +21,7 @@ import ora from 'ora';
|
|
|
14
21
|
* monospace rendering can break.
|
|
15
22
|
*/
|
|
16
23
|
const isWin = process.platform === 'win32';
|
|
17
|
-
|
|
24
|
+
exports.CH = {
|
|
18
25
|
info: 'ℹ',
|
|
19
26
|
warn: '⚠',
|
|
20
27
|
error: '✗',
|
|
@@ -57,67 +64,67 @@ export const CH = {
|
|
|
57
64
|
* Prefer: spinner.stop() then Logger.error(msg) — which writes to
|
|
58
65
|
* stdout — instead of spinner.fail(msg).
|
|
59
66
|
*/
|
|
60
|
-
|
|
67
|
+
function createSpinner(textOrOpts) {
|
|
61
68
|
const opts = typeof textOrOpts === 'string' ? { text: textOrOpts } : textOrOpts;
|
|
62
69
|
// Suppress spinner animation when stderr is not a TTY (piped output,
|
|
63
70
|
// CI, non-interactive terminals). The spinner object still works — its
|
|
64
71
|
// .start()/.stop()/.succeed() methods are no-ops — so callers don't
|
|
65
72
|
// need conditional logic.
|
|
66
73
|
const isSilent = !process.stderr.isTTY;
|
|
67
|
-
return
|
|
74
|
+
return (0, ora_1.default)({ ...opts, stream: process.stderr, isSilent });
|
|
68
75
|
}
|
|
69
|
-
|
|
76
|
+
class Logger {
|
|
70
77
|
verbose = false;
|
|
71
78
|
setVerbose(verbose) {
|
|
72
79
|
this.verbose = verbose;
|
|
73
80
|
}
|
|
74
81
|
debug(...args) {
|
|
75
82
|
if (this.verbose) {
|
|
76
|
-
console.log(
|
|
83
|
+
console.log(chalk_1.default.gray('[DEBUG]'), ...args);
|
|
77
84
|
}
|
|
78
85
|
}
|
|
79
86
|
info(...args) {
|
|
80
|
-
console.log(
|
|
87
|
+
console.log(chalk_1.default.blue(exports.CH.info), ...args);
|
|
81
88
|
}
|
|
82
89
|
warn(...args) {
|
|
83
|
-
console.log(
|
|
90
|
+
console.log(chalk_1.default.yellow(exports.CH.warn), ...args);
|
|
84
91
|
}
|
|
85
92
|
error(...args) {
|
|
86
93
|
// Write error messages to stdout (not stderr) to avoid triggering
|
|
87
94
|
// PowerShell NativeCommandError styling. The red ✗ prefix already
|
|
88
95
|
// signals an error visually; stderr redirection is unnecessary.
|
|
89
|
-
console.log(
|
|
96
|
+
console.log(chalk_1.default.red(exports.CH.error), ...args);
|
|
90
97
|
}
|
|
91
98
|
success(...args) {
|
|
92
|
-
console.log(
|
|
99
|
+
console.log(chalk_1.default.green(exports.CH.success), ...args);
|
|
93
100
|
}
|
|
94
101
|
// AI response formatting
|
|
95
102
|
ai(message) {
|
|
96
|
-
console.log(
|
|
103
|
+
console.log(chalk_1.default.cyan(exports.CH.ai), message);
|
|
97
104
|
}
|
|
98
105
|
// User input formatting
|
|
99
106
|
user(message) {
|
|
100
|
-
console.log(
|
|
107
|
+
console.log(chalk_1.default.white(exports.CH.user), message);
|
|
101
108
|
}
|
|
102
109
|
// Code block
|
|
103
110
|
code(code, language) {
|
|
104
|
-
console.log(
|
|
105
|
-
console.log(
|
|
106
|
-
console.log(
|
|
111
|
+
console.log(chalk_1.default.gray(exports.CH.hLine.repeat(60)));
|
|
112
|
+
console.log(chalk_1.default.yellow(code));
|
|
113
|
+
console.log(chalk_1.default.gray(exports.CH.hLine.repeat(60)));
|
|
107
114
|
}
|
|
108
115
|
// Diff output - enhanced with syntax-highlighted unified diff
|
|
109
116
|
diff(added, removed) {
|
|
110
|
-
removed.forEach(line => console.log(
|
|
111
|
-
added.forEach(line => console.log(
|
|
117
|
+
removed.forEach(line => console.log(chalk_1.default.red(`- ${line}`)));
|
|
118
|
+
added.forEach(line => console.log(chalk_1.default.green(`+ ${line}`)));
|
|
112
119
|
}
|
|
113
120
|
// Unified diff display with file context
|
|
114
121
|
unifiedDiff(filePath, oldText, newText) {
|
|
115
122
|
const oldLines = oldText.split('\n');
|
|
116
123
|
const newLines = newText.split('\n');
|
|
117
124
|
const fileName = filePath.split('/').pop() || filePath;
|
|
118
|
-
console.log(
|
|
119
|
-
console.log(
|
|
120
|
-
console.log(
|
|
125
|
+
console.log(chalk_1.default.bold.white(`\n ${exports.CH.hLine.repeat(3)} ${fileName} ${exports.CH.hLine.repeat(Math.max(1, 50 - fileName.length))}`));
|
|
126
|
+
console.log(chalk_1.default.gray(` --- a/${filePath}`));
|
|
127
|
+
console.log(chalk_1.default.gray(` +++ b/${filePath}`));
|
|
121
128
|
// Find diff ranges with context
|
|
122
129
|
const contextLines = 3;
|
|
123
130
|
let i = 0;
|
|
@@ -133,18 +140,18 @@ export class Logger {
|
|
|
133
140
|
const startNew = Math.max(0, j - contextLines);
|
|
134
141
|
// Context before
|
|
135
142
|
for (let c = startOld; c < i; c++) {
|
|
136
|
-
console.log(
|
|
143
|
+
console.log(chalk_1.default.gray(` ${String(c + 1).padStart(4)} │ ${oldLines[c] || ''}`));
|
|
137
144
|
}
|
|
138
145
|
// Removed lines
|
|
139
146
|
while (i < oldLines.length && (j >= newLines.length || oldLines[i] !== newLines[j])) {
|
|
140
|
-
console.log(
|
|
147
|
+
console.log(chalk_1.default.red(` ${String(i + 1).padStart(4)} │-${oldLines[i]}`));
|
|
141
148
|
i++;
|
|
142
149
|
if (j < newLines.length && (i >= oldLines.length || oldLines[i] === newLines[j]))
|
|
143
150
|
break;
|
|
144
151
|
}
|
|
145
152
|
// Added lines
|
|
146
153
|
while (j < newLines.length && (i >= oldLines.length || oldLines[i] !== newLines[j])) {
|
|
147
|
-
console.log(
|
|
154
|
+
console.log(chalk_1.default.green(` ${String(j + 1).padStart(4)} │+${newLines[j]}`));
|
|
148
155
|
j++;
|
|
149
156
|
if (i < oldLines.length && oldLines[i] === newLines[j])
|
|
150
157
|
break;
|
|
@@ -152,23 +159,23 @@ export class Logger {
|
|
|
152
159
|
// Context after
|
|
153
160
|
const endCtx = Math.min(oldLines.length, i + contextLines);
|
|
154
161
|
for (let c = i; c < endCtx && c < oldLines.length && j < newLines.length && oldLines[c] === newLines[j]; c++) {
|
|
155
|
-
console.log(
|
|
162
|
+
console.log(chalk_1.default.gray(` ${String(c + 1).padStart(4)} │ ${oldLines[c] || ''}`));
|
|
156
163
|
i = c + 1;
|
|
157
164
|
j++;
|
|
158
165
|
}
|
|
159
|
-
console.log(
|
|
166
|
+
console.log(chalk_1.default.gray(` ${exports.CH.hLine.repeat(55)}`));
|
|
160
167
|
}
|
|
161
168
|
console.log();
|
|
162
169
|
}
|
|
163
170
|
// Section header
|
|
164
171
|
section(title) {
|
|
165
172
|
console.log();
|
|
166
|
-
console.log(
|
|
173
|
+
console.log(chalk_1.default.bold.cyan(`${exports.CH.hDouble.repeat(3)} ${title} ${exports.CH.hDouble.repeat(3)}`));
|
|
167
174
|
console.log();
|
|
168
175
|
}
|
|
169
176
|
// Progress
|
|
170
177
|
progress(message) {
|
|
171
|
-
process.stdout.write(
|
|
178
|
+
process.stdout.write(chalk_1.default.gray(`${message}\r`));
|
|
172
179
|
}
|
|
173
180
|
// Clear line
|
|
174
181
|
clearLine() {
|
|
@@ -181,18 +188,18 @@ export class Logger {
|
|
|
181
188
|
const stripAnsi = (str) => str.replace(/\x1B\[[0-9;]*[a-zA-Z]/g, '');
|
|
182
189
|
const maxLen = Math.max(...lines.map(l => stripAnsi(l).length), title?.length || 0);
|
|
183
190
|
const width = maxLen + 4;
|
|
184
|
-
console.log(
|
|
191
|
+
console.log(chalk_1.default.cyan(exports.CH.tl + exports.CH.hLine.repeat(width - 2) + exports.CH.tr));
|
|
185
192
|
if (title) {
|
|
186
|
-
console.log(
|
|
187
|
-
console.log(
|
|
193
|
+
console.log(chalk_1.default.cyan(exports.CH.vLine + ' ') + chalk_1.default.bold.white(title.padEnd(width - 4)) + chalk_1.default.cyan(' ' + exports.CH.vLine));
|
|
194
|
+
console.log(chalk_1.default.cyan(exports.CH.teeR + exports.CH.hLine.repeat(width - 2) + exports.CH.teeL));
|
|
188
195
|
}
|
|
189
196
|
lines.forEach(line => {
|
|
190
197
|
// Calculate visible length and pad accordingly
|
|
191
198
|
const visibleLen = stripAnsi(line).length;
|
|
192
199
|
const padding = ' '.repeat(Math.max(0, width - 4 - visibleLen));
|
|
193
|
-
console.log(
|
|
200
|
+
console.log(chalk_1.default.cyan(exports.CH.vLine + ' ') + line + padding + chalk_1.default.cyan(' ' + exports.CH.vLine));
|
|
194
201
|
});
|
|
195
|
-
console.log(
|
|
202
|
+
console.log(chalk_1.default.cyan(exports.CH.bl + exports.CH.hLine.repeat(width - 2) + exports.CH.br));
|
|
196
203
|
}
|
|
197
204
|
// Table output
|
|
198
205
|
table(headers, rows) {
|
|
@@ -201,18 +208,19 @@ export class Logger {
|
|
|
201
208
|
return Math.max(h.length, maxData);
|
|
202
209
|
});
|
|
203
210
|
// Header
|
|
204
|
-
console.log(
|
|
205
|
-
headers.map((h, i) =>
|
|
206
|
-
|
|
211
|
+
console.log(chalk_1.default.gray(exports.CH.vLine + ' ') +
|
|
212
|
+
headers.map((h, i) => chalk_1.default.bold(h.padEnd(colWidths[i]))).join(chalk_1.default.gray(' ' + exports.CH.vLine + ' ')) +
|
|
213
|
+
chalk_1.default.gray(' ' + exports.CH.vLine));
|
|
207
214
|
// Separator
|
|
208
|
-
console.log(
|
|
209
|
-
colWidths.map(w => CH.hLine.repeat(w)).join(
|
|
210
|
-
|
|
215
|
+
console.log(chalk_1.default.gray(exports.CH.teeR + exports.CH.hLine) +
|
|
216
|
+
colWidths.map(w => exports.CH.hLine.repeat(w)).join(chalk_1.default.gray(exports.CH.hLine + exports.CH.cross + exports.CH.hLine)) +
|
|
217
|
+
chalk_1.default.gray(exports.CH.hLine + exports.CH.teeL));
|
|
211
218
|
// Rows
|
|
212
219
|
rows.forEach(row => {
|
|
213
|
-
console.log(
|
|
214
|
-
row.map((cell, i) => (cell || '').padEnd(colWidths[i])).join(
|
|
215
|
-
|
|
220
|
+
console.log(chalk_1.default.gray(exports.CH.vLine + ' ') +
|
|
221
|
+
row.map((cell, i) => (cell || '').padEnd(colWidths[i])).join(chalk_1.default.gray(' ' + exports.CH.vLine + ' ')) +
|
|
222
|
+
chalk_1.default.gray(' ' + exports.CH.vLine));
|
|
216
223
|
});
|
|
217
224
|
}
|
|
218
225
|
}
|
|
226
|
+
exports.Logger = Logger;
|
package/dist/utils/persona.js
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.normalizePersonaMode = normalizePersonaMode;
|
|
4
|
+
exports.isToneDownPrompt = isToneDownPrompt;
|
|
5
|
+
exports.buildPersonaOverlay = buildPersonaOverlay;
|
|
1
6
|
const WIENER_GRANT_PROMPT = [
|
|
2
7
|
'Optional persona overlay: Wiener Grantler mode.',
|
|
3
8
|
'You remain Vigthoria: technically precise, helpful, safe, and comprehensive.',
|
|
@@ -13,7 +18,7 @@ const TONE_DOWN_PROMPT = [
|
|
|
13
18
|
'Tone-down rule active: this request appears safety-sensitive, destructive, auth/billing-related, security-related, legal/medical/financial, or production-critical.',
|
|
14
19
|
'Use only a very light flavor line if appropriate, then prioritize plain clarity, caution, and exact steps.',
|
|
15
20
|
].join('\n');
|
|
16
|
-
|
|
21
|
+
function normalizePersonaMode(value) {
|
|
17
22
|
const normalized = String(value || '').trim().toLowerCase().replace(/_/g, '-');
|
|
18
23
|
if (!normalized || normalized === 'default' || normalized === 'off' || normalized === 'none')
|
|
19
24
|
return 'default';
|
|
@@ -21,10 +26,10 @@ export function normalizePersonaMode(value) {
|
|
|
21
26
|
return 'wiener_grant';
|
|
22
27
|
return null;
|
|
23
28
|
}
|
|
24
|
-
|
|
29
|
+
function isToneDownPrompt(prompt) {
|
|
25
30
|
return /\b(delete|drop|destroy|wipe|rm\s+-rf|format|credential|secret|token|auth|login|billing|payment|wallet|security|vulnerability|exploit|incident|production|prod|deploy|legal|medical|financial|bank|tax)\b/i.test(prompt);
|
|
26
31
|
}
|
|
27
|
-
|
|
32
|
+
function buildPersonaOverlay(mode, prompt = '') {
|
|
28
33
|
if (mode !== 'wiener_grant')
|
|
29
34
|
return '';
|
|
30
35
|
const parts = [WIENER_GRANT_PROMPT];
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
"use strict";
|
|
1
2
|
/**
|
|
2
3
|
* Vigthoria CLI — Post-Write Validator / Self-Healing Layer
|
|
3
4
|
*
|
|
@@ -8,12 +9,18 @@
|
|
|
8
9
|
*
|
|
9
10
|
* Used by runSelfHealingCycle in api.ts to send targeted correction prompts.
|
|
10
11
|
*/
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
13
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
14
|
+
};
|
|
15
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
+
exports.runPostWriteValidation = runPostWriteValidation;
|
|
17
|
+
exports.formatValidationErrors = formatValidationErrors;
|
|
18
|
+
const node_child_process_1 = require("node:child_process");
|
|
19
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
20
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
14
21
|
function commandExists(cmd, args = ['--version']) {
|
|
15
22
|
try {
|
|
16
|
-
execFileSync(cmd, args, { stdio: 'pipe', timeout: 4000, windowsHide: true });
|
|
23
|
+
(0, node_child_process_1.execFileSync)(cmd, args, { stdio: 'pipe', timeout: 4000, windowsHide: true });
|
|
17
24
|
return true;
|
|
18
25
|
}
|
|
19
26
|
catch {
|
|
@@ -21,23 +28,23 @@ function commandExists(cmd, args = ['--version']) {
|
|
|
21
28
|
}
|
|
22
29
|
}
|
|
23
30
|
function hasTsConfig(dir) {
|
|
24
|
-
return
|
|
31
|
+
return node_fs_1.default.existsSync(node_path_1.default.join(dir, 'tsconfig.json'));
|
|
25
32
|
}
|
|
26
33
|
/**
|
|
27
34
|
* Resolve the best available tsc binary for the project.
|
|
28
35
|
* Prefers local node_modules/.bin/tsc over npx to avoid network fetches.
|
|
29
36
|
*/
|
|
30
37
|
function resolveTscBin(workspacePath) {
|
|
31
|
-
const localTsc =
|
|
32
|
-
if (
|
|
38
|
+
const localTsc = node_path_1.default.join(workspacePath, 'node_modules', '.bin', 'tsc');
|
|
39
|
+
if (node_fs_1.default.existsSync(localTsc))
|
|
33
40
|
return { cmd: localTsc, args: ["--noEmit", "--skipLibCheck"] };
|
|
34
41
|
try {
|
|
35
|
-
execFileSync("npx", ["--version"], { stdio: "pipe", timeout: 4000, windowsHide: true });
|
|
42
|
+
(0, node_child_process_1.execFileSync)("npx", ["--version"], { stdio: "pipe", timeout: 4000, windowsHide: true });
|
|
36
43
|
return { cmd: "npx", args: ["tsc", "--noEmit", "--skipLibCheck"] };
|
|
37
44
|
}
|
|
38
45
|
catch { /* npx not available */ }
|
|
39
46
|
try {
|
|
40
|
-
execFileSync("tsc", ["--version"], { stdio: "pipe", timeout: 4000, windowsHide: true });
|
|
47
|
+
(0, node_child_process_1.execFileSync)("tsc", ["--version"], { stdio: "pipe", timeout: 4000, windowsHide: true });
|
|
41
48
|
return { cmd: "tsc", args: ["--noEmit", "--skipLibCheck"] };
|
|
42
49
|
}
|
|
43
50
|
catch { /* tsc not available */ }
|
|
@@ -45,10 +52,10 @@ function resolveTscBin(workspacePath) {
|
|
|
45
52
|
}
|
|
46
53
|
function hasRealTestScript(dir) {
|
|
47
54
|
try {
|
|
48
|
-
const pkgPath =
|
|
49
|
-
if (!
|
|
55
|
+
const pkgPath = node_path_1.default.join(dir, 'package.json');
|
|
56
|
+
if (!node_fs_1.default.existsSync(pkgPath))
|
|
50
57
|
return false;
|
|
51
|
-
const pkg = JSON.parse(
|
|
58
|
+
const pkg = JSON.parse(node_fs_1.default.readFileSync(pkgPath, 'utf-8'));
|
|
52
59
|
const script = pkg.scripts?.test ?? '';
|
|
53
60
|
return typeof script === 'string' && script.length > 0
|
|
54
61
|
&& !script.startsWith('echo "Error: no test specified"');
|
|
@@ -61,8 +68,8 @@ function hasRealTestScript(dir) {
|
|
|
61
68
|
* Run post-write validation in the project directory.
|
|
62
69
|
* Each check is time-bounded to avoid blocking the CLI.
|
|
63
70
|
*/
|
|
64
|
-
|
|
65
|
-
if (!workspacePath || !
|
|
71
|
+
async function runPostWriteValidation(workspacePath) {
|
|
72
|
+
if (!workspacePath || !node_fs_1.default.existsSync(workspacePath))
|
|
66
73
|
return [];
|
|
67
74
|
const results = [];
|
|
68
75
|
const opts = { cwd: workspacePath, stdio: 'pipe', windowsHide: true };
|
|
@@ -70,7 +77,7 @@ export async function runPostWriteValidation(workspacePath) {
|
|
|
70
77
|
const tscBin = hasTsConfig(workspacePath) ? resolveTscBin(workspacePath) : null;
|
|
71
78
|
if (tscBin) {
|
|
72
79
|
try {
|
|
73
|
-
execFileSync(tscBin.cmd, tscBin.args, { ...opts, timeout: 45_000 });
|
|
80
|
+
(0, node_child_process_1.execFileSync)(tscBin.cmd, tscBin.args, { ...opts, timeout: 45_000 });
|
|
74
81
|
results.push({ ran: true, tool: 'tsc', passed: true, output: '' });
|
|
75
82
|
}
|
|
76
83
|
catch (err) {
|
|
@@ -81,7 +88,7 @@ export async function runPostWriteValidation(workspacePath) {
|
|
|
81
88
|
// 2. npm test
|
|
82
89
|
if (hasRealTestScript(workspacePath) && commandExists('npm')) {
|
|
83
90
|
try {
|
|
84
|
-
execFileSync('npm', ['test', '--', '--passWithNoTests'], { ...opts, timeout: 90_000 });
|
|
91
|
+
(0, node_child_process_1.execFileSync)('npm', ['test', '--', '--passWithNoTests'], { ...opts, timeout: 90_000 });
|
|
85
92
|
results.push({ ran: true, tool: 'npm test', passed: true, output: '' });
|
|
86
93
|
}
|
|
87
94
|
catch (err) {
|
|
@@ -90,13 +97,13 @@ export async function runPostWriteValidation(workspacePath) {
|
|
|
90
97
|
}
|
|
91
98
|
}
|
|
92
99
|
// 3. Python syntax check
|
|
93
|
-
const hasPy =
|
|
94
|
-
||
|
|
95
|
-
||
|
|
100
|
+
const hasPy = node_fs_1.default.existsSync(node_path_1.default.join(workspacePath, 'requirements.txt'))
|
|
101
|
+
|| node_fs_1.default.existsSync(node_path_1.default.join(workspacePath, 'setup.py'))
|
|
102
|
+
|| node_fs_1.default.existsSync(node_path_1.default.join(workspacePath, 'pyproject.toml'));
|
|
96
103
|
if (hasPy && commandExists('python3', ['-c', 'import ast'])) {
|
|
97
104
|
const pyFiles = [];
|
|
98
105
|
try {
|
|
99
|
-
const entries =
|
|
106
|
+
const entries = node_fs_1.default.readdirSync(workspacePath, { withFileTypes: true });
|
|
100
107
|
for (const e of entries) {
|
|
101
108
|
if (e.isFile() && e.name.endsWith('.py'))
|
|
102
109
|
pyFiles.push(e.name);
|
|
@@ -107,7 +114,7 @@ export async function runPostWriteValidation(workspacePath) {
|
|
|
107
114
|
let pyOut = '';
|
|
108
115
|
for (const pyFile of pyFiles.slice(0, 20)) {
|
|
109
116
|
try {
|
|
110
|
-
execFileSync('python3', ['-m', 'py_compile', pyFile], { ...opts, timeout: 10_000 });
|
|
117
|
+
(0, node_child_process_1.execFileSync)('python3', ['-m', 'py_compile', pyFile], { ...opts, timeout: 10_000 });
|
|
111
118
|
}
|
|
112
119
|
catch (err) {
|
|
113
120
|
pyPassed = false;
|
|
@@ -123,7 +130,7 @@ export async function runPostWriteValidation(workspacePath) {
|
|
|
123
130
|
/**
|
|
124
131
|
* Build a clear error summary string from failed validation results.
|
|
125
132
|
*/
|
|
126
|
-
|
|
133
|
+
function formatValidationErrors(results) {
|
|
127
134
|
return results
|
|
128
135
|
.filter((r) => r.ran && !r.passed)
|
|
129
136
|
.map((r) => `[${r.tool}]\n${r.output.trim()}`)
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
"use strict";
|
|
1
2
|
/**
|
|
2
3
|
* Vigthoria Project Memory Service
|
|
3
4
|
*
|
|
@@ -5,9 +6,14 @@
|
|
|
5
6
|
* compact facts that can be retrieved for follow-up prompts without replaying
|
|
6
7
|
* full chat history or noisy tool traces.
|
|
7
8
|
*/
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
10
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
11
|
+
};
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.ProjectMemoryService = void 0;
|
|
14
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
15
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
16
|
+
const node_crypto_1 = require("node:crypto");
|
|
11
17
|
const MAX_ITEMS = 240;
|
|
12
18
|
const MAX_TEXT_LENGTH = 320;
|
|
13
19
|
const MAX_CONTEXT_ITEMS = 14;
|
|
@@ -29,7 +35,7 @@ function clampText(value, max = MAX_TEXT_LENGTH) {
|
|
|
29
35
|
return normalized.length > max ? `${normalized.slice(0, max - 3)}...` : normalized;
|
|
30
36
|
}
|
|
31
37
|
function slugHash(value) {
|
|
32
|
-
return createHash('sha1').update(value).digest('hex').slice(0, 12);
|
|
38
|
+
return (0, node_crypto_1.createHash)('sha1').update(value).digest('hex').slice(0, 12);
|
|
33
39
|
}
|
|
34
40
|
function tokenize(value) {
|
|
35
41
|
return Array.from(new Set(String(value || '')
|
|
@@ -59,22 +65,22 @@ function inferTags(text) {
|
|
|
59
65
|
tags.add('validation');
|
|
60
66
|
return Array.from(tags).slice(0, 8);
|
|
61
67
|
}
|
|
62
|
-
|
|
68
|
+
class ProjectMemoryService {
|
|
63
69
|
workspacePath;
|
|
64
70
|
memoryDir;
|
|
65
71
|
brainPath;
|
|
66
72
|
constructor(workspacePath = process.cwd()) {
|
|
67
|
-
this.workspacePath =
|
|
68
|
-
this.memoryDir =
|
|
69
|
-
this.brainPath =
|
|
73
|
+
this.workspacePath = node_path_1.default.resolve(workspacePath || process.cwd());
|
|
74
|
+
this.memoryDir = node_path_1.default.join(this.workspacePath, '.vigthoria', 'memory');
|
|
75
|
+
this.brainPath = node_path_1.default.join(this.memoryDir, 'brain.json');
|
|
70
76
|
}
|
|
71
77
|
getMemoryDir() {
|
|
72
78
|
return this.memoryDir;
|
|
73
79
|
}
|
|
74
80
|
loadBrain() {
|
|
75
81
|
try {
|
|
76
|
-
if (
|
|
77
|
-
const parsed = JSON.parse(
|
|
82
|
+
if (node_fs_1.default.existsSync(this.brainPath)) {
|
|
83
|
+
const parsed = JSON.parse(node_fs_1.default.readFileSync(this.brainPath, 'utf8'));
|
|
78
84
|
if (parsed && parsed.version === 1 && Array.isArray(parsed.items)) {
|
|
79
85
|
return parsed;
|
|
80
86
|
}
|
|
@@ -85,21 +91,21 @@ export class ProjectMemoryService {
|
|
|
85
91
|
}
|
|
86
92
|
return {
|
|
87
93
|
version: 1,
|
|
88
|
-
workspaceName:
|
|
94
|
+
workspaceName: node_path_1.default.basename(this.workspacePath),
|
|
89
95
|
updatedAt: nowIso(),
|
|
90
96
|
items: [],
|
|
91
97
|
};
|
|
92
98
|
}
|
|
93
99
|
saveBrain(brain) {
|
|
94
100
|
try {
|
|
95
|
-
|
|
101
|
+
node_fs_1.default.mkdirSync(this.memoryDir, { recursive: true });
|
|
96
102
|
const normalized = {
|
|
97
103
|
...brain,
|
|
98
|
-
workspaceName: brain.workspaceName ||
|
|
104
|
+
workspaceName: brain.workspaceName || node_path_1.default.basename(this.workspacePath),
|
|
99
105
|
updatedAt: nowIso(),
|
|
100
106
|
items: this.dedupeAndTrim(brain.items || []),
|
|
101
107
|
};
|
|
102
|
-
|
|
108
|
+
node_fs_1.default.writeFileSync(this.brainPath, JSON.stringify(normalized, null, 2) + '\n', 'utf8');
|
|
103
109
|
this.writeMarkdownViews(normalized);
|
|
104
110
|
}
|
|
105
111
|
catch {
|
|
@@ -270,10 +276,10 @@ export class ProjectMemoryService {
|
|
|
270
276
|
continue;
|
|
271
277
|
const heading = this.headingForType(type);
|
|
272
278
|
const lines = [`# ${heading}`, '', ...items.map((item) => `- ${item.text}`)];
|
|
273
|
-
|
|
279
|
+
node_fs_1.default.writeFileSync(node_path_1.default.join(this.memoryDir, `${type}s.md`), lines.join('\n') + '\n', 'utf8');
|
|
274
280
|
allLines.push(`## ${heading}`, '', ...items.slice(-40).map((item) => `- ${item.text}`), '');
|
|
275
281
|
}
|
|
276
|
-
|
|
282
|
+
node_fs_1.default.writeFileSync(node_path_1.default.join(this.memoryDir, 'README.md'), allLines.join('\n').trimEnd() + '\n', 'utf8');
|
|
277
283
|
}
|
|
278
284
|
headingForType(type) {
|
|
279
285
|
switch (type) {
|
|
@@ -287,3 +293,4 @@ export class ProjectMemoryService {
|
|
|
287
293
|
}
|
|
288
294
|
}
|
|
289
295
|
}
|
|
296
|
+
exports.ProjectMemoryService = ProjectMemoryService;
|