agen-vektor 0.1.0
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/LICENSE +21 -0
- package/README.md +212 -0
- package/dist/agent/agent.js +90 -0
- package/dist/agent/context.js +106 -0
- package/dist/agent/loop.js +152 -0
- package/dist/agent/memory.js +87 -0
- package/dist/agent/planner.js +38 -0
- package/dist/agent/prompts.js +41 -0
- package/dist/agent/session.js +125 -0
- package/dist/cli/index.js +304 -0
- package/dist/cli/keyboard.js +283 -0
- package/dist/config/config.js +92 -0
- package/dist/config/credentials.js +127 -0
- package/dist/config/models.js +47 -0
- package/dist/providers/anthropic.js +276 -0
- package/dist/providers/custom.js +24 -0
- package/dist/providers/factory.js +58 -0
- package/dist/providers/gemini.js +223 -0
- package/dist/providers/ollama.js +195 -0
- package/dist/providers/openai-compat.js +296 -0
- package/dist/providers/openai.js +17 -0
- package/dist/providers/openrouter.js +23 -0
- package/dist/providers/provider.js +39 -0
- package/dist/security/command-policy.js +99 -0
- package/dist/security/permissions.js +66 -0
- package/dist/tools/filesystem.js +297 -0
- package/dist/tools/git.js +66 -0
- package/dist/tools/registry.js +39 -0
- package/dist/tools/search.js +184 -0
- package/dist/tools/shell.js +108 -0
- package/dist/tools/web.js +76 -0
- package/dist/tui/app.js +913 -0
- package/dist/tui/chat.js +76 -0
- package/dist/tui/components.js +85 -0
- package/dist/tui/diff.js +105 -0
- package/dist/tui/input.js +121 -0
- package/dist/tui/statusbar.js +32 -0
- package/dist/utils/logger.js +96 -0
- package/dist/utils/paths.js +90 -0
- package/dist/utils/terminal.js +191 -0
- package/package.json +56 -0
package/dist/tui/chat.js
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.renderMessages = renderMessages;
|
|
4
|
+
exports.defaultScroll = defaultScroll;
|
|
5
|
+
exports.clampScroll = clampScroll;
|
|
6
|
+
/**
|
|
7
|
+
* Chat view — renders conversation messages with scrolling.
|
|
8
|
+
* Message types: user, assistant (streamed), tool, system/status, plan.
|
|
9
|
+
*/
|
|
10
|
+
const terminal_1 = require("../utils/terminal");
|
|
11
|
+
const KIND_STYLE = {
|
|
12
|
+
user: { prefix: 'YOU', color: terminal_1.ANSI.brightBlue },
|
|
13
|
+
assistant: { prefix: 'VECTOR', color: terminal_1.ANSI.brightGreen },
|
|
14
|
+
tool: { prefix: 'TOOL', color: terminal_1.ANSI.brightYellow },
|
|
15
|
+
system: { prefix: '···', color: terminal_1.ANSI.gray },
|
|
16
|
+
error: { prefix: '✗', color: terminal_1.ANSI.brightRed },
|
|
17
|
+
success: { prefix: '✓', color: terminal_1.ANSI.brightGreen },
|
|
18
|
+
warning: { prefix: '⚠', color: terminal_1.ANSI.brightYellow },
|
|
19
|
+
};
|
|
20
|
+
function plainLines(text, width) {
|
|
21
|
+
const lines = text.split('\n');
|
|
22
|
+
const out = [];
|
|
23
|
+
for (const l of lines) {
|
|
24
|
+
if (l.length <= width) {
|
|
25
|
+
out.push(l);
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
for (let i = 0; i < l.length; i += width)
|
|
29
|
+
out.push(l.slice(i, i + width));
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return out;
|
|
33
|
+
}
|
|
34
|
+
/** Precompute the full list of rendered lines for all messages. */
|
|
35
|
+
function renderMessages(messages, width) {
|
|
36
|
+
const out = [];
|
|
37
|
+
for (const m of messages) {
|
|
38
|
+
const style = KIND_STYLE[m.kind];
|
|
39
|
+
const prefix = m.prefix || style.prefix;
|
|
40
|
+
const header = `${style.color}${terminal_1.ANSI.bold}${prefix}${terminal_1.ANSI.reset}${m.streaming ? terminal_1.ANSI.blink + ' ▍' + terminal_1.ANSI.reset : ''}`;
|
|
41
|
+
const headerLine = m.tool ? `${header} ${terminal_1.ANSI.dim}${m.tool}${terminal_1.ANSI.reset}` : header;
|
|
42
|
+
out.push(headerLine);
|
|
43
|
+
const body = m.content || '(no content)';
|
|
44
|
+
for (const line of plainLines(body, width)) {
|
|
45
|
+
if (m.kind === 'user') {
|
|
46
|
+
out.push(`${terminal_1.ANSI.brightBlue}│ ${line}${terminal_1.ANSI.reset}`);
|
|
47
|
+
}
|
|
48
|
+
else if (m.kind === 'tool') {
|
|
49
|
+
out.push(`${terminal_1.ANSI.brightYellow}│ ${line}${terminal_1.ANSI.reset}`);
|
|
50
|
+
}
|
|
51
|
+
else if (m.kind === 'error') {
|
|
52
|
+
out.push(`${terminal_1.ANSI.brightRed}│ ${line}${terminal_1.ANSI.reset}`);
|
|
53
|
+
}
|
|
54
|
+
else if (m.kind === 'success') {
|
|
55
|
+
out.push(`${terminal_1.ANSI.brightGreen}│ ${line}${terminal_1.ANSI.reset}`);
|
|
56
|
+
}
|
|
57
|
+
else if (m.kind === 'warning') {
|
|
58
|
+
out.push(`${terminal_1.ANSI.brightYellow}│ ${line}${terminal_1.ANSI.reset}`);
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
out.push(` ${line}`);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
out.push(''); // blank line between messages
|
|
65
|
+
}
|
|
66
|
+
return out;
|
|
67
|
+
}
|
|
68
|
+
function defaultScroll(messages, width, height) {
|
|
69
|
+
const all = renderMessages(messages, width);
|
|
70
|
+
return Math.max(0, all.length - height);
|
|
71
|
+
}
|
|
72
|
+
function clampScroll(offset, messages, width, height) {
|
|
73
|
+
const all = renderMessages(messages, width);
|
|
74
|
+
const max = Math.max(0, all.length - height);
|
|
75
|
+
return Math.min(Math.max(0, offset), max);
|
|
76
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.renderModal = renderModal;
|
|
4
|
+
exports.renderSelector = renderSelector;
|
|
5
|
+
/**
|
|
6
|
+
* Reusable TUI components — modal overlay and list selector.
|
|
7
|
+
*/
|
|
8
|
+
const terminal_1 = require("../utils/terminal");
|
|
9
|
+
/** Render a centered modal box. Returns the box's top row (1-based). */
|
|
10
|
+
function renderModal(opts, rows, cols) {
|
|
11
|
+
const title = opts.title;
|
|
12
|
+
const innerWidth = Math.max(10, Math.min(cols - 4, opts.width || Math.max(30, cols - 10)));
|
|
13
|
+
const bodyLines = opts.body.flatMap((b) => (0, terminal_1.wrapText)(b, innerWidth - 2));
|
|
14
|
+
const footerLines = opts.footer ? (0, terminal_1.wrapText)(opts.footer, innerWidth - 2) : [];
|
|
15
|
+
const height = Math.min(rows - 2, bodyLines.length + footerLines.length + 4);
|
|
16
|
+
const top = Math.max(1, Math.floor((rows - height) / 2));
|
|
17
|
+
const left = Math.max(1, Math.floor((cols - innerWidth - 2) / 2));
|
|
18
|
+
const borderColor = opts.danger ? terminal_1.ANSI.brightRed : terminal_1.ANSI.cyan;
|
|
19
|
+
const lines = [];
|
|
20
|
+
const topBorder = borderColor + terminal_1.BOX.tl + terminal_1.BOX.h.repeat(innerWidth) + terminal_1.BOX.tr;
|
|
21
|
+
const bottomBorder = borderColor + terminal_1.BOX.bl + terminal_1.BOX.h.repeat(innerWidth) + terminal_1.BOX.br;
|
|
22
|
+
// Title placement
|
|
23
|
+
const t = (0, terminal_1.pad)(title.slice(0, innerWidth - 2), innerWidth);
|
|
24
|
+
lines.push((0, terminal_1.cursorTo)(top, left) +
|
|
25
|
+
topBorder.slice(0, 2) +
|
|
26
|
+
terminal_1.ANSI.bold + terminal_1.ANSI.white + t + terminal_1.ANSI.reset + borderColor +
|
|
27
|
+
topBorder.slice(2));
|
|
28
|
+
const maxBody = height - footerLines.length - 2;
|
|
29
|
+
for (let i = 0; i < maxBody; i++) {
|
|
30
|
+
const content = bodyLines[i] ?? '';
|
|
31
|
+
const lineStr = (0, terminal_1.pad)(content, innerWidth);
|
|
32
|
+
lines.push((0, terminal_1.cursorTo)(top + 1 + i, left) + borderColor + terminal_1.BOX.v + ' ' + lineStr + terminal_1.ANSI.reset + borderColor + ' ' + terminal_1.BOX.v);
|
|
33
|
+
}
|
|
34
|
+
for (let i = 0; i < footerLines.length; i++) {
|
|
35
|
+
const row = top + 1 + maxBody + i;
|
|
36
|
+
const content = footerLines[i] ?? '';
|
|
37
|
+
const lineStr = (0, terminal_1.pad)(content, innerWidth);
|
|
38
|
+
lines.push((0, terminal_1.cursorTo)(row, left) + borderColor + terminal_1.BOX.v + ' ' + terminal_1.ANSI.dim + lineStr + terminal_1.ANSI.reset + borderColor + ' ' + terminal_1.BOX.v);
|
|
39
|
+
}
|
|
40
|
+
lines.push((0, terminal_1.cursorTo)(top + height - 1, left) + bottomBorder);
|
|
41
|
+
return { top, lines };
|
|
42
|
+
}
|
|
43
|
+
/** Render a list selector (menu) — used for /model, /provider, /session. */
|
|
44
|
+
function renderSelector(opts) {
|
|
45
|
+
const innerWidth = Math.max(10, Math.min(opts.cols - 4, opts.title.length + 4));
|
|
46
|
+
const visible = Math.min(opts.options.length, Math.max(3, opts.rows - 6));
|
|
47
|
+
const start = Math.max(0, opts.selected - Math.floor(visible / 2));
|
|
48
|
+
const height = visible + 3;
|
|
49
|
+
const top = Math.max(1, Math.floor((opts.rows - height) / 2));
|
|
50
|
+
const left = Math.max(1, Math.floor((opts.cols - innerWidth - 2) / 2));
|
|
51
|
+
const lines = [];
|
|
52
|
+
const borderColor = terminal_1.ANSI.cyan;
|
|
53
|
+
const t = (0, terminal_1.pad)(opts.title.slice(0, innerWidth - 2), innerWidth);
|
|
54
|
+
lines.push((0, terminal_1.cursorTo)(top, left) +
|
|
55
|
+
borderColor + terminal_1.BOX.tl + terminal_1.BOX.h.repeat(2) +
|
|
56
|
+
terminal_1.ANSI.bold + terminal_1.ANSI.white + t + terminal_1.ANSI.reset + borderColor +
|
|
57
|
+
terminal_1.BOX.h.repeat(Math.max(0, innerWidth - 2 - (0, terminal_1.visibleWidth)(t))) + terminal_1.BOX.tr);
|
|
58
|
+
for (let i = 0; i < visible; i++) {
|
|
59
|
+
const idx = start + i;
|
|
60
|
+
const row = top + 1 + i;
|
|
61
|
+
const option = opts.options[idx];
|
|
62
|
+
let content;
|
|
63
|
+
if (option) {
|
|
64
|
+
const marker = idx === opts.selected ? '▸ ' : ' ';
|
|
65
|
+
const label = marker + option.label;
|
|
66
|
+
const hint = option.hint ? terminal_1.ANSI.dim + ' — ' + option.hint + terminal_1.ANSI.reset : '';
|
|
67
|
+
if (idx === opts.selected) {
|
|
68
|
+
content = terminal_1.ANSI.bold + terminal_1.ANSI.cyan + (0, terminal_1.pad)(label, innerWidth - (0, terminal_1.visibleWidth)(hint)) + terminal_1.ANSI.reset + hint;
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
content = (0, terminal_1.pad)(label, innerWidth - (0, terminal_1.visibleWidth)(hint)) + hint;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
content = ' '.repeat(innerWidth);
|
|
76
|
+
}
|
|
77
|
+
lines.push((0, terminal_1.cursorTo)(row, left) + borderColor + terminal_1.BOX.v + ' ' + content + terminal_1.ANSI.reset + ' ' + terminal_1.BOX.v);
|
|
78
|
+
}
|
|
79
|
+
const footerText = opts.footer ? opts.footer : '↑↓ navigate · Enter select · Esc cancel';
|
|
80
|
+
const f = (0, terminal_1.pad)(footerText.slice(0, innerWidth - 2), innerWidth);
|
|
81
|
+
lines.push((0, terminal_1.cursorTo)(top + visible + 1, left) +
|
|
82
|
+
borderColor + terminal_1.BOX.bl + terminal_1.BOX.h.repeat(2) + terminal_1.ANSI.dim + f + terminal_1.ANSI.reset + borderColor +
|
|
83
|
+
terminal_1.BOX.h.repeat(Math.max(0, innerWidth - 2 - (0, terminal_1.visibleWidth)(f))) + terminal_1.BOX.br);
|
|
84
|
+
return { top, lines };
|
|
85
|
+
}
|
package/dist/tui/diff.js
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.diffLines = diffLines;
|
|
4
|
+
exports.computeDiff = computeDiff;
|
|
5
|
+
exports.renderDiffModal = renderDiffModal;
|
|
6
|
+
/**
|
|
7
|
+
* Diff viewer — renders unified diffs with color, plus a
|
|
8
|
+
* modal with Accept / Reject actions.
|
|
9
|
+
*/
|
|
10
|
+
const terminal_1 = require("../utils/terminal");
|
|
11
|
+
const components_1 = require("./components");
|
|
12
|
+
/** Compute a minimal unified diff between two strings (line-based). */
|
|
13
|
+
function diffLines(oldText, newText) {
|
|
14
|
+
return computeDiff(oldText, newText);
|
|
15
|
+
}
|
|
16
|
+
function computeDiff(oldText, newText) {
|
|
17
|
+
const oldLines = (oldText || '').split('\n');
|
|
18
|
+
const newLines = (newText || '').split('\n');
|
|
19
|
+
// Simple LCS-based diff for small files; falls back to full replace view.
|
|
20
|
+
if (oldLines.length * newLines.length > 250_000) {
|
|
21
|
+
const out = ['- (old) file content:'];
|
|
22
|
+
for (const l of oldLines)
|
|
23
|
+
out.push(`- ${l}`);
|
|
24
|
+
out.push('+ (new) file content:');
|
|
25
|
+
for (const l of newLines)
|
|
26
|
+
out.push(`+ ${l}`);
|
|
27
|
+
return out;
|
|
28
|
+
}
|
|
29
|
+
const ops = lcsDiff(oldLines, newLines);
|
|
30
|
+
const out = [];
|
|
31
|
+
for (const op of ops) {
|
|
32
|
+
if (op.type === 'same')
|
|
33
|
+
out.push(` ${op.line}`);
|
|
34
|
+
else if (op.type === 'del')
|
|
35
|
+
out.push(`${terminal_1.ANSI.red}- ${op.line}${terminal_1.ANSI.reset}`);
|
|
36
|
+
else
|
|
37
|
+
out.push(`${terminal_1.ANSI.green}+ ${op.line}${terminal_1.ANSI.reset}`);
|
|
38
|
+
}
|
|
39
|
+
return out;
|
|
40
|
+
}
|
|
41
|
+
function lcsDiff(a, b) {
|
|
42
|
+
const n = a.length;
|
|
43
|
+
const m = b.length;
|
|
44
|
+
// DP table
|
|
45
|
+
const dp = Array.from({ length: n + 1 }, () => new Array(m + 1).fill(0));
|
|
46
|
+
for (let i = n - 1; i >= 0; i--) {
|
|
47
|
+
for (let j = m - 1; j >= 0; j--) {
|
|
48
|
+
if (a[i] === b[j])
|
|
49
|
+
dp[i][j] = dp[i + 1][j + 1] + 1;
|
|
50
|
+
else
|
|
51
|
+
dp[i][j] = Math.max(dp[i + 1][j], dp[i][j + 1]);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
const out = [];
|
|
55
|
+
let i = 0;
|
|
56
|
+
let j = 0;
|
|
57
|
+
while (i < n && j < m) {
|
|
58
|
+
if (a[i] === b[j]) {
|
|
59
|
+
out.push({ type: 'same', line: a[i] });
|
|
60
|
+
i++;
|
|
61
|
+
j++;
|
|
62
|
+
}
|
|
63
|
+
else if (dp[i + 1][j] >= dp[i][j + 1]) {
|
|
64
|
+
out.push({ type: 'del', line: a[i] });
|
|
65
|
+
i++;
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
out.push({ type: 'add', line: b[j] });
|
|
69
|
+
j++;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
while (i < n) {
|
|
73
|
+
out.push({ type: 'del', line: a[i] });
|
|
74
|
+
i++;
|
|
75
|
+
}
|
|
76
|
+
while (j < m) {
|
|
77
|
+
out.push({ type: 'add', line: b[j] });
|
|
78
|
+
j++;
|
|
79
|
+
}
|
|
80
|
+
return out;
|
|
81
|
+
}
|
|
82
|
+
/** Render the diff modal with a header per file. */
|
|
83
|
+
function renderDiffModal(entries, rows, cols, scroll, selectedAccept) {
|
|
84
|
+
const innerWidth = Math.max(20, cols - 4);
|
|
85
|
+
const body = [];
|
|
86
|
+
for (const e of entries) {
|
|
87
|
+
body.push(`${terminal_1.ANSI.bold}${terminal_1.ANSI.brightCyan}── ${e.path}${terminal_1.ANSI.reset}`);
|
|
88
|
+
const diffLines = computeDiff(e.oldContent || '', e.newContent);
|
|
89
|
+
body.push(...diffLines);
|
|
90
|
+
body.push('');
|
|
91
|
+
}
|
|
92
|
+
// Scroll window
|
|
93
|
+
const visibleLines = Math.max(3, rows - 6);
|
|
94
|
+
const maxScroll = Math.max(0, body.length - visibleLines);
|
|
95
|
+
const s = Math.min(scroll, maxScroll);
|
|
96
|
+
const windowLines = body.slice(s, s + visibleLines);
|
|
97
|
+
const footer = `${selectedAccept === 'accept' ? terminal_1.ANSI.bold + terminal_1.ANSI.green + '[Accept]' + terminal_1.ANSI.reset : '[Accept]'} ${selectedAccept === 'reject' ? terminal_1.ANSI.bold + terminal_1.ANSI.red + '[Reject]' + terminal_1.ANSI.reset : '[Reject]'} ↑↓ scroll · ←→ choose · Enter confirm · Esc cancel`;
|
|
98
|
+
const modal = (0, components_1.renderModal)({
|
|
99
|
+
title: `Diff — ${entries.length} file(s)`,
|
|
100
|
+
body: windowLines,
|
|
101
|
+
footer,
|
|
102
|
+
width: innerWidth,
|
|
103
|
+
}, rows, cols);
|
|
104
|
+
return { top: modal.top, lines: modal.lines };
|
|
105
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.InputBox = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Input box — single-line text input with cursor, history, and hints.
|
|
6
|
+
*/
|
|
7
|
+
const terminal_1 = require("../utils/terminal");
|
|
8
|
+
class InputBox {
|
|
9
|
+
text = '';
|
|
10
|
+
cursor = 0;
|
|
11
|
+
history = [];
|
|
12
|
+
historyIndex = -1;
|
|
13
|
+
hint = '';
|
|
14
|
+
setHint(hint) {
|
|
15
|
+
this.hint = hint;
|
|
16
|
+
}
|
|
17
|
+
get value() {
|
|
18
|
+
return this.text;
|
|
19
|
+
}
|
|
20
|
+
setValue(v) {
|
|
21
|
+
this.text = v;
|
|
22
|
+
this.cursor = v.length;
|
|
23
|
+
}
|
|
24
|
+
clear() {
|
|
25
|
+
this.text = '';
|
|
26
|
+
this.cursor = 0;
|
|
27
|
+
this.historyIndex = -1;
|
|
28
|
+
}
|
|
29
|
+
pushHistory(s) {
|
|
30
|
+
if (!s.trim())
|
|
31
|
+
return;
|
|
32
|
+
this.history = [s, ...this.history.filter((h) => h !== s)].slice(0, 100);
|
|
33
|
+
this.historyIndex = -1;
|
|
34
|
+
}
|
|
35
|
+
insert(ch) {
|
|
36
|
+
this.text = this.text.slice(0, this.cursor) + ch + this.text.slice(this.cursor);
|
|
37
|
+
this.cursor += ch.length;
|
|
38
|
+
}
|
|
39
|
+
backspace() {
|
|
40
|
+
if (this.cursor <= 0)
|
|
41
|
+
return;
|
|
42
|
+
this.text = this.text.slice(0, this.cursor - 1) + this.text.slice(this.cursor);
|
|
43
|
+
this.cursor--;
|
|
44
|
+
}
|
|
45
|
+
deleteForward() {
|
|
46
|
+
if (this.cursor >= this.text.length)
|
|
47
|
+
return;
|
|
48
|
+
this.text = this.text.slice(0, this.cursor) + this.text.slice(this.cursor + 1);
|
|
49
|
+
}
|
|
50
|
+
moveLeft() {
|
|
51
|
+
this.cursor = Math.max(0, this.cursor - 1);
|
|
52
|
+
}
|
|
53
|
+
moveRight() {
|
|
54
|
+
this.cursor = Math.min(this.text.length, this.cursor + 1);
|
|
55
|
+
}
|
|
56
|
+
moveHome() {
|
|
57
|
+
this.cursor = 0;
|
|
58
|
+
}
|
|
59
|
+
moveEnd() {
|
|
60
|
+
this.cursor = this.text.length;
|
|
61
|
+
}
|
|
62
|
+
deleteToStart() {
|
|
63
|
+
this.text = this.text.slice(this.cursor);
|
|
64
|
+
this.cursor = 0;
|
|
65
|
+
}
|
|
66
|
+
deleteWordBack() {
|
|
67
|
+
const before = this.text.slice(0, this.cursor);
|
|
68
|
+
const m = before.match(/\S+\s*$/);
|
|
69
|
+
if (m) {
|
|
70
|
+
this.text = before.slice(0, before.length - m[0].length) + this.text.slice(this.cursor);
|
|
71
|
+
this.cursor = before.length - m[0].length;
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
this.backspace();
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
historyPrev() {
|
|
78
|
+
if (this.history.length === 0)
|
|
79
|
+
return;
|
|
80
|
+
if (this.historyIndex < this.history.length - 1) {
|
|
81
|
+
this.historyIndex++;
|
|
82
|
+
this.text = this.history[this.historyIndex];
|
|
83
|
+
this.cursor = this.text.length;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
historyNext() {
|
|
87
|
+
if (this.historyIndex <= -1)
|
|
88
|
+
return;
|
|
89
|
+
this.historyIndex--;
|
|
90
|
+
if (this.historyIndex === -1) {
|
|
91
|
+
this.text = '';
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
this.text = this.history[this.historyIndex];
|
|
95
|
+
}
|
|
96
|
+
this.cursor = this.text.length;
|
|
97
|
+
}
|
|
98
|
+
/** Render the input line, returns the cursor column (0-based within line). */
|
|
99
|
+
render(width) {
|
|
100
|
+
const prefix = '❯ ';
|
|
101
|
+
const available = Math.max(1, width - prefix.length - 1);
|
|
102
|
+
let display = this.text;
|
|
103
|
+
let cursorCol = prefix.length + this.cursor;
|
|
104
|
+
if (this.text.length > available) {
|
|
105
|
+
// Scroll window around the cursor
|
|
106
|
+
let start = this.cursor - Math.floor(available / 2);
|
|
107
|
+
start = Math.max(0, Math.min(start, this.text.length - available));
|
|
108
|
+
display = this.text.slice(start, start + available);
|
|
109
|
+
cursorCol = prefix.length + (this.cursor - start);
|
|
110
|
+
}
|
|
111
|
+
let suffix = '';
|
|
112
|
+
if (!this.text && this.hint) {
|
|
113
|
+
suffix = terminal_1.ANSI.dim + this.hint + terminal_1.ANSI.reset;
|
|
114
|
+
}
|
|
115
|
+
return {
|
|
116
|
+
line: `${terminal_1.ANSI.brightGreen}${prefix}${terminal_1.ANSI.reset}${display}${suffix}`,
|
|
117
|
+
cursorCol,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
exports.InputBox = InputBox;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.renderStatusBar = renderStatusBar;
|
|
4
|
+
exports.renderHeader = renderHeader;
|
|
5
|
+
exports.renderProjectBar = renderProjectBar;
|
|
6
|
+
/**
|
|
7
|
+
* Status bar — bottom hint bar + top header rendering.
|
|
8
|
+
*/
|
|
9
|
+
const terminal_1 = require("../utils/terminal");
|
|
10
|
+
function renderStatusBar(info, width) {
|
|
11
|
+
const left = `ENTER Send · TAB Commands · CTRL+C Stop · ? Help`;
|
|
12
|
+
const right = `${info.connected ? terminal_1.ANSI.green + '●' : terminal_1.ANSI.red + '○'}${terminal_1.ANSI.reset} ${info.mode === 'yolo' ? terminal_1.ANSI.yellow + 'YOLO' + terminal_1.ANSI.reset : 'ask'}`;
|
|
13
|
+
const leftWidth = width - right.length - 1;
|
|
14
|
+
return terminal_1.ANSI.bgBlack + (0, terminal_1.pad)(left.slice(0, Math.max(0, leftWidth)), Math.max(0, leftWidth)) + right + terminal_1.ANSI.reset;
|
|
15
|
+
}
|
|
16
|
+
function renderHeader(width, info) {
|
|
17
|
+
const brand = `${terminal_1.ANSI.bold}${terminal_1.ANSI.brightCyan}VECTOR${terminal_1.ANSI.reset}`;
|
|
18
|
+
const status = `${info.statusColor}●${terminal_1.ANSI.reset} ${info.status}`;
|
|
19
|
+
const left = `${brand} ${status}`;
|
|
20
|
+
const right = `${terminal_1.ANSI.dim}${info.provider}${terminal_1.ANSI.reset} · ${info.model}`;
|
|
21
|
+
const rightWidth = visible(right);
|
|
22
|
+
const leftWidth = Math.max(0, width - rightWidth - 2);
|
|
23
|
+
const line = (0, terminal_1.pad)(left, leftWidth) + ' ' + right;
|
|
24
|
+
return terminal_1.ANSI.bgBlack + (0, terminal_1.pad)(line, width) + terminal_1.ANSI.reset;
|
|
25
|
+
}
|
|
26
|
+
function renderProjectBar(width, info) {
|
|
27
|
+
const line = `${terminal_1.ANSI.dim}Project:${terminal_1.ANSI.reset} ${info.project} ${terminal_1.ANSI.dim}Mode:${terminal_1.ANSI.reset} ${info.mode === 'yolo' ? terminal_1.ANSI.yellow + 'yolo' + terminal_1.ANSI.reset : 'ask'}`;
|
|
28
|
+
return terminal_1.ANSI.bgBlack + (0, terminal_1.pad)(line, width) + terminal_1.ANSI.reset;
|
|
29
|
+
}
|
|
30
|
+
function visible(s) {
|
|
31
|
+
return s.replace(/\x1b\[[0-9;]*[A-Za-z]/g, '').length;
|
|
32
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
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.logger = void 0;
|
|
37
|
+
/**
|
|
38
|
+
* Minimal file logger — writes to ~/.vector/logs/vector.log
|
|
39
|
+
* Never logs secrets: callers must sanitize.
|
|
40
|
+
*/
|
|
41
|
+
const fs = __importStar(require("node:fs"));
|
|
42
|
+
const path = __importStar(require("node:path"));
|
|
43
|
+
const paths_1 = require("./paths");
|
|
44
|
+
const LEVEL_ORDER = {
|
|
45
|
+
debug: 10,
|
|
46
|
+
info: 20,
|
|
47
|
+
warn: 30,
|
|
48
|
+
error: 40,
|
|
49
|
+
};
|
|
50
|
+
let currentLevel = process.env.VECTOR_LOG_LEVEL || 'info';
|
|
51
|
+
let logFile = null;
|
|
52
|
+
function ensureLogFile() {
|
|
53
|
+
if (logFile)
|
|
54
|
+
return logFile;
|
|
55
|
+
try {
|
|
56
|
+
const dir = path.join((0, paths_1.getVectorDir)(), 'logs');
|
|
57
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
58
|
+
logFile = path.join(dir, 'vector.log');
|
|
59
|
+
return logFile;
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
function write(level, msg) {
|
|
66
|
+
if (LEVEL_ORDER[level] < LEVEL_ORDER[currentLevel])
|
|
67
|
+
return;
|
|
68
|
+
const ts = new Date().toISOString();
|
|
69
|
+
const entry = `[${ts}] [${level.toUpperCase()}] ${msg}`;
|
|
70
|
+
const file = ensureLogFile();
|
|
71
|
+
if (file) {
|
|
72
|
+
try {
|
|
73
|
+
fs.appendFileSync(file, entry + '\n');
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
/* ignore */
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
exports.logger = {
|
|
81
|
+
setLevel(level) {
|
|
82
|
+
currentLevel = level;
|
|
83
|
+
},
|
|
84
|
+
debug(msg) {
|
|
85
|
+
write('debug', msg);
|
|
86
|
+
},
|
|
87
|
+
info(msg) {
|
|
88
|
+
write('info', msg);
|
|
89
|
+
},
|
|
90
|
+
warn(msg) {
|
|
91
|
+
write('warn', msg);
|
|
92
|
+
},
|
|
93
|
+
error(msg) {
|
|
94
|
+
write('error', msg);
|
|
95
|
+
},
|
|
96
|
+
};
|
|
@@ -0,0 +1,90 @@
|
|
|
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.getVectorDir = getVectorDir;
|
|
37
|
+
exports.getConfigPath = getConfigPath;
|
|
38
|
+
exports.getProvidersPath = getProvidersPath;
|
|
39
|
+
exports.getModelsPath = getModelsPath;
|
|
40
|
+
exports.getCredentialsPath = getCredentialsPath;
|
|
41
|
+
exports.getSessionsDir = getSessionsDir;
|
|
42
|
+
exports.getMemoryDir = getMemoryDir;
|
|
43
|
+
exports.getLogsDir = getLogsDir;
|
|
44
|
+
exports.ensureDirs = ensureDirs;
|
|
45
|
+
exports.sanitizeName = sanitizeName;
|
|
46
|
+
/**
|
|
47
|
+
* Path helpers for the VECTOR config directory (~/.vector).
|
|
48
|
+
*/
|
|
49
|
+
const fs = __importStar(require("node:fs"));
|
|
50
|
+
const os = __importStar(require("node:os"));
|
|
51
|
+
const path = __importStar(require("node:path"));
|
|
52
|
+
function getVectorDir() {
|
|
53
|
+
return process.env.VECTOR_HOME || path.join(os.homedir(), '.vector');
|
|
54
|
+
}
|
|
55
|
+
function getConfigPath() {
|
|
56
|
+
return path.join(getVectorDir(), 'config.json');
|
|
57
|
+
}
|
|
58
|
+
function getProvidersPath() {
|
|
59
|
+
return path.join(getVectorDir(), 'providers.json');
|
|
60
|
+
}
|
|
61
|
+
function getModelsPath() {
|
|
62
|
+
return path.join(getVectorDir(), 'models.json');
|
|
63
|
+
}
|
|
64
|
+
function getCredentialsPath() {
|
|
65
|
+
return path.join(getVectorDir(), 'credentials.json');
|
|
66
|
+
}
|
|
67
|
+
function getSessionsDir() {
|
|
68
|
+
return path.join(getVectorDir(), 'sessions');
|
|
69
|
+
}
|
|
70
|
+
function getMemoryDir() {
|
|
71
|
+
return path.join(getVectorDir(), 'memory');
|
|
72
|
+
}
|
|
73
|
+
function getLogsDir() {
|
|
74
|
+
return path.join(getVectorDir(), 'logs');
|
|
75
|
+
}
|
|
76
|
+
/** Ensure all vector dirs exist. */
|
|
77
|
+
function ensureDirs() {
|
|
78
|
+
for (const d of [
|
|
79
|
+
getVectorDir(),
|
|
80
|
+
getSessionsDir(),
|
|
81
|
+
getMemoryDir(),
|
|
82
|
+
getLogsDir(),
|
|
83
|
+
]) {
|
|
84
|
+
fs.mkdirSync(d, { recursive: true });
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
/** Sanitize a session name into a safe filename. */
|
|
88
|
+
function sanitizeName(name) {
|
|
89
|
+
return name.replace(/[^a-zA-Z0-9._-]/g, '_');
|
|
90
|
+
}
|