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 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
  ```
@@ -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, expose the
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);
@@ -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 identifies users by the anonymous
13
- * device id sent via the X-Vector-Device header, so no real key exists —
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 keys users by X-Vector-Device, not
153
- // by a secret. Inline (not {env:}) so no env var is ever required.
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
- errorContent = '⚠️ Kuota VectorHead Free untuk perangkat ini sudah habis — coba lagi besok, atau pakai API key sendiri via /connect (BYOK).';
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agen-vektor",
3
- "version": "0.3.13",
3
+ "version": "0.3.14",
4
4
  "description": "VectorHead (agen-vektor) — AI Coding Agent CLI/TUI for Linux & Termux. Multi-provider, tool calling, session, permission system.",
5
5
  "type": "commonjs",
6
6
  "bin": {