agen-vektor 0.3.13 → 0.3.14
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 +18 -1
- package/dist/agent/agent.js +3 -4
- package/dist/config/free-tier.js +7 -78
- package/dist/tui/app.js +6 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -50,7 +50,7 @@ incrementally with no flicker.
|
|
|
50
50
|
## Contents
|
|
51
51
|
|
|
52
52
|
- [Features](#features) · [Installation](#installation) · [Quick start](#quick-start) · [Command line](#command-line) · [TUI commands](#tui-commands)
|
|
53
|
-
- [Provider configuration](#provider-configuration) · [Themes](#themes) · [Security model](#security-model) · [Architecture](#architecture) · [Development](#development)
|
|
53
|
+
- [Provider configuration](#provider-configuration) · [Themes](#themes) · [Security model](#security-model) · [Privacy](#privacy) · [Architecture](#architecture) · [Development](#development)
|
|
54
54
|
- [Testing](#testing) · [Troubleshooting](#troubleshooting) · [Roadmap](#roadmap) · [License](#license)
|
|
55
55
|
|
|
56
56
|
## Features
|
|
@@ -307,6 +307,23 @@ Every shell command is classified:
|
|
|
307
307
|
|
|
308
308
|
`--yolo` auto-approves ASK-level actions but still prompts for DANGEROUS and refuses BLOCKED ones. API keys are never printed to the terminal, logs, diffs, or session history.
|
|
309
309
|
|
|
310
|
+
## Privacy
|
|
311
|
+
|
|
312
|
+
**VectorHead collects nothing.** No telemetry, no analytics, no crash reporting, no usage tracking — there is no code in the app that could phone home. Every network destination in the source is auditable:
|
|
313
|
+
|
|
314
|
+
| Destination | When |
|
|
315
|
+
|---|---|
|
|
316
|
+
| Your configured AI provider (OpenAI, Anthropic, Gemini, OpenRouter, Ollama, custom) | Only when you chat — with **your own** API key |
|
|
317
|
+
| `vector-tui.methatech.eu.org` (VectorHead Free gateway) | Only if you pick the free tier; the shared provider key stays server-side, users never see it |
|
|
318
|
+
| Brave / Exa / Serper | Only when you use the web-search tool with your own key |
|
|
319
|
+
| Raw model catalog (public JSON) | To populate the free-tier model list |
|
|
320
|
+
|
|
321
|
+
**Stored locally** (all in `~/.vector/`): `config.json` (preferences, no secrets), `credentials.json` (only keys *you* enter, file mode 0600), sessions, memory, logs. Nothing else is written anywhere.
|
|
322
|
+
|
|
323
|
+
**No device identity.** The app does not generate a device id or send any tracking header (the old anonymous `device-id` + `X-Vector-Device` pair was fully removed in 0.3.14).
|
|
324
|
+
|
|
325
|
+
**The agent guards itself against secrets** — its own file tools refuse to read or write `.env`, private keys, `credentials.json`, kubeconfig, and similar files (override only via explicit `VECTOR_ALLOW_SENSITIVE=1`), so a prompt cannot accidentally exfiltrate them.
|
|
326
|
+
|
|
310
327
|
## Architecture
|
|
311
328
|
|
|
312
329
|
```
|
package/dist/agent/agent.js
CHANGED
|
@@ -64,14 +64,13 @@ class Agent {
|
|
|
64
64
|
permissions;
|
|
65
65
|
cwd;
|
|
66
66
|
constructor(opts) {
|
|
67
|
-
// Free tier (vectorhead-free): define the provider entry
|
|
68
|
-
// anonymous device id for the {env:} header template, and default a
|
|
67
|
+
// Free tier (vectorhead-free): define the provider entry and default a
|
|
69
68
|
// FIRST RUN (no config.json yet) to the free tier so onboarding is
|
|
70
69
|
// "install & pick a model" with zero keys. Existing configs keep their
|
|
71
|
-
// active provider; only the free ENTRY is (re)defined.
|
|
70
|
+
// active provider; only the free ENTRY is (re)defined. No per-device
|
|
71
|
+
// identity: the gateway requires none (X-Vector-Device removed 2026-09-05).
|
|
72
72
|
const firstRun = !opts.config && (0, free_tier_1.isFirstRun)(fs.existsSync((0, paths_1.getConfigPath)()));
|
|
73
73
|
const seeded = (0, config_1.effectiveConfig)(opts.config);
|
|
74
|
-
(0, free_tier_1.exportDeviceIdEnv)();
|
|
75
74
|
if ((0, free_tier_1.ensureFreeProvider)(seeded)) {
|
|
76
75
|
try {
|
|
77
76
|
(0, config_1.saveConfig)(seeded);
|
package/dist/config/free-tier.js
CHANGED
|
@@ -9,65 +9,25 @@
|
|
|
9
9
|
*
|
|
10
10
|
* Design:
|
|
11
11
|
* - `vectorhead-free` is an OpenCode-style entry in config.providers with an
|
|
12
|
-
* INLINE placeholder key. The gateway
|
|
13
|
-
*
|
|
12
|
+
* INLINE placeholder key. The gateway holds the real provider key as a
|
|
13
|
+
* server-side secret and does NOT require any per-device or per-user
|
|
14
|
+
* identity from the client (per-device quota was removed 2026-09-05 —
|
|
15
|
+
* X-Vector-Device is no longer sent), so no real key exists client-side —
|
|
14
16
|
* the inline placeholder simply satisfies "custom providers need a key"
|
|
15
17
|
* checks without storing anything secret on the user's disk.
|
|
16
|
-
* - The device id lives in ~/.vector/device-id (NOT config.json, so config
|
|
17
|
-
* stays copyable between machines; a copied device id would merge two
|
|
18
|
-
* users into one quota bucket). Header templating "{env:VECTOR_DEVICE_ID}"
|
|
19
|
-
* resolves at request time via providerHeaders().
|
|
20
18
|
* - First run (no config.json): the agent starts on this provider so a new
|
|
21
19
|
* user can chat immediately — pick BYOK later via /connect. An EXISTING
|
|
22
20
|
* config is never touched except to (re)define the free provider entry.
|
|
23
21
|
*/
|
|
24
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
25
|
-
if (k2 === undefined) k2 = k;
|
|
26
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
27
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
28
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
29
|
-
}
|
|
30
|
-
Object.defineProperty(o, k2, desc);
|
|
31
|
-
}) : (function(o, m, k, k2) {
|
|
32
|
-
if (k2 === undefined) k2 = k;
|
|
33
|
-
o[k2] = m[k];
|
|
34
|
-
}));
|
|
35
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
36
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
37
|
-
}) : function(o, v) {
|
|
38
|
-
o["default"] = v;
|
|
39
|
-
});
|
|
40
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
41
|
-
var ownKeys = function(o) {
|
|
42
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
43
|
-
var ar = [];
|
|
44
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
45
|
-
return ar;
|
|
46
|
-
};
|
|
47
|
-
return ownKeys(o);
|
|
48
|
-
};
|
|
49
|
-
return function (mod) {
|
|
50
|
-
if (mod && mod.__esModule) return mod;
|
|
51
|
-
var result = {};
|
|
52
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
53
|
-
__setModuleDefault(result, mod);
|
|
54
|
-
return result;
|
|
55
|
-
};
|
|
56
|
-
})();
|
|
57
22
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
58
23
|
exports.FREE_DEFAULT_MODEL = exports.FREE_PROVIDER_ID = exports.CATALOG_TTL_MS = exports.FREE_CATALOG_URL = exports.FREE_GATEWAY_CATALOG_URL = exports.FREE_GATEWAY_URL = void 0;
|
|
59
24
|
exports.resetFreeCatalogCache = resetFreeCatalogCache;
|
|
60
25
|
exports.freeTierEnabled = freeTierEnabled;
|
|
61
|
-
exports.ensureDeviceId = ensureDeviceId;
|
|
62
|
-
exports.exportDeviceIdEnv = exportDeviceIdEnv;
|
|
63
26
|
exports.freeProviderDef = freeProviderDef;
|
|
64
27
|
exports.ensureFreeProvider = ensureFreeProvider;
|
|
65
28
|
exports.isFirstRun = isFirstRun;
|
|
66
29
|
exports.fetchFreeCatalog = fetchFreeCatalog;
|
|
67
30
|
exports.applyFreeCatalog = applyFreeCatalog;
|
|
68
|
-
const fs = __importStar(require("node:fs"));
|
|
69
|
-
const crypto = __importStar(require("node:crypto"));
|
|
70
|
-
const paths_1 = require("../utils/paths");
|
|
71
31
|
/** Public gateway base URL (custom Cloudflare domain — stable, no ports). */
|
|
72
32
|
exports.FREE_GATEWAY_URL = 'https://vector-tui.methatech.eu.org/v1';
|
|
73
33
|
/**
|
|
@@ -100,37 +60,6 @@ function freeTierEnabled() {
|
|
|
100
60
|
exports.FREE_PROVIDER_ID = 'vectorhead-free';
|
|
101
61
|
/** Default free model (cheap, gateway allowlist-friendly). */
|
|
102
62
|
exports.FREE_DEFAULT_MODEL = 'deepseek-ai/DeepSeek-V4-Flash';
|
|
103
|
-
/** File holding the anonymous per-device id. */
|
|
104
|
-
function devicePath() {
|
|
105
|
-
return process.env.VECTOR_DEVICE_FILE || ((0, paths_1.getVectorDir)() + '/device-id');
|
|
106
|
-
}
|
|
107
|
-
/** Device id for the anonymous free tier: create on first use, reuse after. */
|
|
108
|
-
function ensureDeviceId() {
|
|
109
|
-
try {
|
|
110
|
-
const p = devicePath();
|
|
111
|
-
if (fs.existsSync(p)) {
|
|
112
|
-
const existing = fs.readFileSync(p, 'utf8').trim();
|
|
113
|
-
if (/^[a-f0-9][a-f0-9-]{7,63}$/.test(existing))
|
|
114
|
-
return existing;
|
|
115
|
-
}
|
|
116
|
-
const fresh = crypto.randomUUID();
|
|
117
|
-
fs.writeFileSync(p, fresh + '\n', { mode: 0o600 });
|
|
118
|
-
return fresh;
|
|
119
|
-
}
|
|
120
|
-
catch {
|
|
121
|
-
// Read-only fs etc. — fall back to an ephemeral id for this session.
|
|
122
|
-
return crypto.randomUUID();
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
/** Export the current device id into the env for {env:} header templates. */
|
|
126
|
-
function exportDeviceIdEnv() {
|
|
127
|
-
try {
|
|
128
|
-
process.env.VECTOR_DEVICE_ID = ensureDeviceId();
|
|
129
|
-
}
|
|
130
|
-
catch {
|
|
131
|
-
/* never block startup on this */
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
63
|
/** The providers-map entry for the free tier (idempotent — same shape always). */
|
|
135
64
|
function freeProviderDef() {
|
|
136
65
|
// When a catalog has been fetched in this process, the gateway URL and
|
|
@@ -149,10 +78,10 @@ function freeProviderDef() {
|
|
|
149
78
|
name: 'VectorHead Free',
|
|
150
79
|
options: {
|
|
151
80
|
baseURL: (cat && typeof cat.gateway === 'string' && cat.gateway ? cat.gateway : exports.FREE_GATEWAY_URL),
|
|
152
|
-
// Placeholder ONLY — the gateway
|
|
153
|
-
//
|
|
81
|
+
// Placeholder ONLY — the gateway holds the real provider key as a
|
|
82
|
+
// server-side secret and accepts anonymous requests. Inline (not
|
|
83
|
+
// {env:}) so no env var is ever required.
|
|
154
84
|
apiKey: 'vectorhead-free-anonymous',
|
|
155
|
-
headers: { 'X-Vector-Device': '{env:VECTOR_DEVICE_ID}' },
|
|
156
85
|
},
|
|
157
86
|
model: exports.FREE_DEFAULT_MODEL,
|
|
158
87
|
models: Object.keys(models).length > 0 ? models : {
|
package/dist/tui/app.js
CHANGED
|
@@ -1642,7 +1642,11 @@ class App {
|
|
|
1642
1642
|
// line instead of a raw HTTP error — the dot still turns red above.
|
|
1643
1643
|
let errorContent = `⚠️ ${err.message}`;
|
|
1644
1644
|
if (exhausted && this.agent.config.provider === free_tier_1.FREE_PROVIDER_ID) {
|
|
1645
|
-
|
|
1645
|
+
// TIDAK ada kuota perangkat di tier free (dihapus dari gateway).
|
|
1646
|
+
// Error quota di sini = cooldown key GATEWAY (akun bersama), bukan
|
|
1647
|
+
// kesalahan user — jangan menuduh kuota habis.
|
|
1648
|
+
errorContent =
|
|
1649
|
+
'⚠️ Key gateway VectorHead Free sedang cooldown sebentar (dipakai akun bersama) — coba lagi beberapa menit, atau ganti model via /model, atau pakai API key sendiri via /connect (BYOK).';
|
|
1646
1650
|
}
|
|
1647
1651
|
this.messages.push({ kind: 'error', content: errorContent, ts: Date.now() });
|
|
1648
1652
|
this.scrollToLatest();
|
|
@@ -2704,8 +2708,7 @@ class App {
|
|
|
2704
2708
|
if (c.provider === 'ollama')
|
|
2705
2709
|
return true;
|
|
2706
2710
|
// Named custom provider: an INLINE key in its definition (OpenCode
|
|
2707
|
-
// options.apiKey) makes it usable as-is — the free tier ships exactly
|
|
2708
|
-
// that (placeholder key + X-Vector-Device auth), so picking "VectorHead
|
|
2711
|
+
// options.apiKey) makes it usable as-is — the free tier ships exactly // that (placeholder key, no device identity), so picking "VectorHead
|
|
2709
2712
|
// Free" in /connect must light the header up immediately.
|
|
2710
2713
|
if ((0, providers_1.isCustomProvider)(c, c.provider))
|
|
2711
2714
|
return !!(0, providers_1.providerApiKey)(c, c.provider);
|
package/package.json
CHANGED