vibeostheog 0.20.3 → 0.20.4
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/CHANGELOG.md +8 -0
- package/README.md +5 -3
- package/package.json +1 -1
- package/src/lib/api-client.js +131 -55
- package/src/lib/hooks/footer.js +17 -14
- package/src/lib/trinity-tool.js +10 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
## 0.20.4
|
|
2
|
+
- fix: add alpha token invalidate switch
|
|
3
|
+
- fix: prefer valid api tokens over placeholder env
|
|
4
|
+
- fix: gate footer stderr by runtime
|
|
5
|
+
- fix: quiet footer stderr noise
|
|
6
|
+
Merge pull request #70 from DrunkkToys/codex/alpha-token-kill-switch
|
|
7
|
+
|
|
8
|
+
|
|
1
9
|
## 0.20.3
|
|
2
10
|
- fix: embed valid alpha token fallback
|
|
3
11
|
Merge pull request #69 from DrunkkToys/codex/alpha-token-release
|
package/README.md
CHANGED
|
@@ -30,6 +30,7 @@ Without a token, vibeOS keeps running in local-only mode with bundled algorithms
|
|
|
30
30
|
### Requires Remote API
|
|
31
31
|
|
|
32
32
|
- Bootstrap token exchange (required for initial API setup)
|
|
33
|
+
- Alpha seat issuance is currently uncapped in the admin tooling
|
|
33
34
|
- Advanced VibeBoX decision engine with full session history tracking
|
|
34
35
|
- Dynamic per-prompt delegation decisions (local fallback uses a safe "block all writes on high tier" default)
|
|
35
36
|
- Learned subagent routing patterns across projects (local fallback uses a static exploratory keyword list)
|
|
@@ -111,7 +112,7 @@ The most common controls are:
|
|
|
111
112
|
- `trinity repair-state preview|apply` - fix state fingerprint collisions
|
|
112
113
|
- `trinity VibeBoX on|off|status|reset` - control the decision engine
|
|
113
114
|
- `trinity guard` - refresh AGENTS.md and README.md checks
|
|
114
|
-
- `trinity api-token <token>` - update the remote API token
|
|
115
|
+
- `trinity api-token <token|invalidate>` - update the remote API token, or invalidate the current alpha token and disable remote API
|
|
115
116
|
- `trinity api-bootstrap-token <token>` - store an alpha bootstrap token and exchange it for a normal API token on alpha builds
|
|
116
117
|
|
|
117
118
|
Additional reporting commands:
|
|
@@ -138,7 +139,8 @@ Savings are persisted in `~/.claude/delegation-state.json`.
|
|
|
138
139
|
| Variable | Default | Purpose |
|
|
139
140
|
|---|---|---|
|
|
140
141
|
| `VIBEOS_API_URL` | `https://api.vibetheog.com` | Remote API server URL |
|
|
141
|
-
| `VIBEOS_API_TOKEN` | unset |
|
|
142
|
+
| `VIBEOS_API_TOKEN` | unset | vos_8d73804b13bb46711b9a47f036dba7b4d026fd9583d96960e663716e62815a69 |
|
|
143
|
+
| `VIBEOS_API_DISABLED` | `false` | Set to `true` to invalidate the embedded alpha token and keep remote API off until re-enabled |
|
|
142
144
|
| `VIBEOS_API_BOOTSTRAP_TOKEN` | unset | Alpha bootstrap token for initial auth exchange |
|
|
143
145
|
| `VIBEOS_API_ENABLED` | `true` | Set to `false` for local-only mode |
|
|
144
146
|
| `CLAUDE_CREDIT_PERCENT` | `100` | Credit override |
|
|
@@ -154,7 +156,7 @@ Without a token, vibeOS keeps running in local-only mode with bundled algorithms
|
|
|
154
156
|
- If the model will not switch, run `trinity rebuild` and then `trinity set brain|medium|cheap`.
|
|
155
157
|
- If writes or edits are blocked, that is usually delegation enforcement working as intended on the brain tier.
|
|
156
158
|
- If the footer is missing, check that the plugin is enabled and that the current OpenCode session is receiving assistant completions.
|
|
157
|
-
- If the remote API is down or the token is invalid, use `trinity api-token <token>` or `trinity api-bootstrap-token <token>` on alpha builds
|
|
159
|
+
- If the remote API is down or the token is invalid, use `trinity api-token <token>` or `trinity api-bootstrap-token <token>` on alpha builds. Use `trinity api-token invalidate` when you want to intentionally revoke the alpha token and stay local-only.
|
|
158
160
|
- If the dashboard does not load, rebuild the plugin with `npm run build` and restart OpenCode.
|
|
159
161
|
- If state or config looks inconsistent, run `trinity diagnose` and `trinity guard`.
|
|
160
162
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vibeostheog",
|
|
3
|
-
"version": "0.20.
|
|
3
|
+
"version": "0.20.4",
|
|
4
4
|
"description": "Cost-aware delegation enforcer for OpenCode. Tracks model usage, routes Task subagents to cheaper tiers, surfaces cumulative savings in chat. Includes research audit, reporting framework, project memory, progressive scratchpad decadence, and trinity CLI for brain/medium/cheap slot switching.",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"release": "node scripts/release.mjs",
|
package/src/lib/api-client.js
CHANGED
|
@@ -5,7 +5,9 @@ import { fileURLToPath } from "node:url";
|
|
|
5
5
|
import { homedir } from "node:os";
|
|
6
6
|
import { isApiConnected as isRuntimeApiConnected, markApiConnected, markApiDisconnected, resetApiConnection } from "./runtime-state.js";
|
|
7
7
|
const DEFAULT_API_URL = "https://api.vibetheog.com";
|
|
8
|
-
const EMBEDDED_API_TOKEN = "
|
|
8
|
+
const EMBEDDED_API_TOKEN = "vos_8d73804b13bb46711b9a47f036dba7b4d026fd9583d96960e663716e62815a69";
|
|
9
|
+
const API_TOKEN_RE = /^vos_[a-f0-9]{64}$/i;
|
|
10
|
+
const API_DISABLED_RE = /^(1|true|yes|on)$/i;
|
|
9
11
|
const REQUEST_TIMEOUT = 10000;
|
|
10
12
|
const MAX_RETRIES = 3;
|
|
11
13
|
const BASE_RETRY_DELAY = 1000;
|
|
@@ -34,6 +36,59 @@ export class VibeOSNetworkError extends Error {
|
|
|
34
36
|
this.name = "VibeOSNetworkError";
|
|
35
37
|
}
|
|
36
38
|
}
|
|
39
|
+
function normalizeApiToken(token, fallback = "") {
|
|
40
|
+
const clean = String(token || "").trim();
|
|
41
|
+
return API_TOKEN_RE.test(clean) ? clean : fallback;
|
|
42
|
+
}
|
|
43
|
+
function isTruthyFlag(value) {
|
|
44
|
+
return API_DISABLED_RE.test(String(value || "").trim());
|
|
45
|
+
}
|
|
46
|
+
function editEnvLine(content, key, value) {
|
|
47
|
+
const lines = String(content || "").split(/\r?\n/);
|
|
48
|
+
const next = [];
|
|
49
|
+
let found = false;
|
|
50
|
+
for (const line of lines) {
|
|
51
|
+
if (line.startsWith(`${key}=`)) {
|
|
52
|
+
found = true;
|
|
53
|
+
if (value !== null)
|
|
54
|
+
next.push(`${key}=${value}`);
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
next.push(line);
|
|
58
|
+
}
|
|
59
|
+
if (!found && value !== null)
|
|
60
|
+
next.push(`${key}=${value}`);
|
|
61
|
+
while (next.length > 0 && next[next.length - 1] === "")
|
|
62
|
+
next.pop();
|
|
63
|
+
return next.join("\n") + "\n";
|
|
64
|
+
}
|
|
65
|
+
function persistPrimaryApiEnvState(next) {
|
|
66
|
+
const primaryPath = _envPaths[0] + "/.env.production";
|
|
67
|
+
try {
|
|
68
|
+
let envContent = existsSync(primaryPath) ? readFileSync(primaryPath, "utf8") : "";
|
|
69
|
+
if (next.disabled !== undefined) {
|
|
70
|
+
envContent = editEnvLine(envContent, "VIBEOS_API_DISABLED", next.disabled ? "true" : null);
|
|
71
|
+
}
|
|
72
|
+
if (next.token !== undefined) {
|
|
73
|
+
envContent = editEnvLine(envContent, "VIBEOS_API_TOKEN", next.token ? String(next.token).trim() : null);
|
|
74
|
+
}
|
|
75
|
+
if (!envContent.trim()) {
|
|
76
|
+
try {
|
|
77
|
+
if (existsSync(primaryPath))
|
|
78
|
+
rmSync(primaryPath, { force: true });
|
|
79
|
+
}
|
|
80
|
+
catch { }
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
const parentDir = _envPaths[0];
|
|
84
|
+
if (!existsSync(parentDir))
|
|
85
|
+
mkdirSync(parentDir, { recursive: true });
|
|
86
|
+
writeFileSync(primaryPath, envContent.endsWith("\n") ? envContent : envContent + "\n", "utf8");
|
|
87
|
+
}
|
|
88
|
+
catch (diskErr) {
|
|
89
|
+
console.error("[vibeOS] Failed to persist API env state:", diskErr.message);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
37
92
|
export class VibeOSApiClient {
|
|
38
93
|
baseUrl;
|
|
39
94
|
apiToken;
|
|
@@ -43,7 +98,7 @@ export class VibeOSApiClient {
|
|
|
43
98
|
fallbackStubs;
|
|
44
99
|
constructor(options = {}) {
|
|
45
100
|
this.baseUrl = options.baseUrl || process.env.VIBEOS_API_URL || DEFAULT_API_URL;
|
|
46
|
-
this.apiToken = options.apiToken || process.env.VIBEOS_API_TOKEN || null;
|
|
101
|
+
this.apiToken = normalizeApiToken(options.apiToken || process.env.VIBEOS_API_TOKEN || "", "") || null;
|
|
47
102
|
this.masterKey = options.masterKey || process.env.VIBEOS_API_MASTER_KEY || null;
|
|
48
103
|
this.timeout = options.timeout || REQUEST_TIMEOUT;
|
|
49
104
|
this.fallbackMode = false;
|
|
@@ -306,19 +361,38 @@ export const VIBEOS_API_URL = process.env.VIBEOS_API_URL || "https://api.vibethe
|
|
|
306
361
|
const _apiDir = typeof __dirname !== "undefined" ? __dirname : dirname(fileURLToPath(import.meta.url));
|
|
307
362
|
const _envPaths = [homedir() + "/.claude", _apiDir, process.cwd(), homedir()];
|
|
308
363
|
const _bootstrapEnvPath = _envPaths[0] + "/.env.alpha";
|
|
364
|
+
function readApiDisabledFromDisk() {
|
|
365
|
+
for (const dir of _envPaths) {
|
|
366
|
+
try {
|
|
367
|
+
const env = readFileSync(dir + "/.env.production", "utf8");
|
|
368
|
+
const m = env.match(/^VIBEOS_API_DISABLED=(.+)$/m);
|
|
369
|
+
if (m && isTruthyFlag(m[1]))
|
|
370
|
+
return true;
|
|
371
|
+
}
|
|
372
|
+
catch { }
|
|
373
|
+
}
|
|
374
|
+
return false;
|
|
375
|
+
}
|
|
309
376
|
function readTokenFromDisk() {
|
|
377
|
+
if (readApiDisabledFromDisk())
|
|
378
|
+
return "";
|
|
310
379
|
for (const dir of _envPaths) {
|
|
311
380
|
try {
|
|
312
381
|
const env = readFileSync(dir + "/.env.production", "utf8");
|
|
313
382
|
const m = env.match(/^VIBEOS_API_TOKEN=(.+)$/m);
|
|
314
|
-
if (m)
|
|
315
|
-
|
|
383
|
+
if (m) {
|
|
384
|
+
const clean = normalizeApiToken(m[1], "");
|
|
385
|
+
if (clean)
|
|
386
|
+
return clean;
|
|
387
|
+
}
|
|
316
388
|
}
|
|
317
389
|
catch { }
|
|
318
390
|
}
|
|
319
391
|
return "";
|
|
320
392
|
}
|
|
321
393
|
function readBootstrapTokenFromDisk() {
|
|
394
|
+
if (readApiDisabledFromDisk())
|
|
395
|
+
return "";
|
|
322
396
|
try {
|
|
323
397
|
const env = readFileSync(_bootstrapEnvPath, "utf8");
|
|
324
398
|
const m = env.match(/^VIBEOS_API_BOOTSTRAP_TOKEN=(.+)$/m);
|
|
@@ -328,9 +402,10 @@ function readBootstrapTokenFromDisk() {
|
|
|
328
402
|
catch { }
|
|
329
403
|
return "";
|
|
330
404
|
}
|
|
331
|
-
export let
|
|
332
|
-
export let
|
|
333
|
-
export let
|
|
405
|
+
export let VIBEOS_API_DISABLED = readApiDisabledFromDisk() || isTruthyFlag(process.env.VIBEOS_API_DISABLED);
|
|
406
|
+
export let VIBEOS_API_TOKEN = VIBEOS_API_DISABLED ? "" : (readTokenFromDisk() || normalizeApiToken(process.env.VIBEOS_API_TOKEN, "") || EMBEDDED_API_TOKEN);
|
|
407
|
+
export let VIBEOS_API_BOOTSTRAP_TOKEN = VIBEOS_API_DISABLED ? "" : (readBootstrapTokenFromDisk() || process.env.VIBEOS_API_BOOTSTRAP_TOKEN || "");
|
|
408
|
+
export let VIBEOS_API_ENABLED = !VIBEOS_API_DISABLED && process.env.VIBEOS_API_ENABLED !== "false" && (!!VIBEOS_API_TOKEN || !!VIBEOS_API_BOOTSTRAP_TOKEN);
|
|
334
409
|
function persistBootstrapToken(token) {
|
|
335
410
|
const clean = String(token || "").trim();
|
|
336
411
|
try {
|
|
@@ -353,40 +428,41 @@ function persistBootstrapToken(token) {
|
|
|
353
428
|
}
|
|
354
429
|
export function setApiToken(newToken) {
|
|
355
430
|
try {
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
let envContent = readFileSync(primaryPath, "utf8");
|
|
362
|
-
if (/^VIBEOS_API_TOKEN=/m.test(envContent)) {
|
|
363
|
-
envContent = envContent.replace(/^VIBEOS_API_TOKEN=.+$/m, `VIBEOS_API_TOKEN=${VIBEOS_API_TOKEN}`);
|
|
364
|
-
}
|
|
365
|
-
else {
|
|
366
|
-
envContent = envContent.trimEnd() + `\nVIBEOS_API_TOKEN=${VIBEOS_API_TOKEN}\n`;
|
|
367
|
-
}
|
|
368
|
-
writeFileSync(primaryPath, envContent, "utf8");
|
|
369
|
-
}
|
|
370
|
-
else {
|
|
371
|
-
const parentDir = _envPaths[0];
|
|
372
|
-
if (!existsSync(parentDir))
|
|
373
|
-
mkdirSync(parentDir, { recursive: true });
|
|
374
|
-
writeFileSync(primaryPath, `VIBEOS_API_TOKEN=${VIBEOS_API_TOKEN}\n`, "utf8");
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
|
-
catch (diskErr) {
|
|
378
|
-
console.error("[vibeOS] Failed to persist API token to disk:", diskErr.message);
|
|
379
|
-
}
|
|
431
|
+
VIBEOS_API_DISABLED = false;
|
|
432
|
+
VIBEOS_API_TOKEN = normalizeApiToken(newToken, EMBEDDED_API_TOKEN);
|
|
433
|
+
VIBEOS_API_BOOTSTRAP_TOKEN = readBootstrapTokenFromDisk() || VIBEOS_API_BOOTSTRAP_TOKEN;
|
|
434
|
+
VIBEOS_API_ENABLED = process.env.VIBEOS_API_ENABLED !== "false" && (!!VIBEOS_API_TOKEN || !!VIBEOS_API_BOOTSTRAP_TOKEN);
|
|
435
|
+
persistPrimaryApiEnvState({ token: VIBEOS_API_TOKEN, disabled: false });
|
|
380
436
|
console.error("[vibeOS] API token updated via setApiToken");
|
|
381
437
|
}
|
|
382
438
|
catch (e) {
|
|
383
439
|
console.error("[vibeOS] Failed to update API token:", e.message);
|
|
384
440
|
}
|
|
385
441
|
}
|
|
442
|
+
export function invalidateApiToken() {
|
|
443
|
+
try {
|
|
444
|
+
VIBEOS_API_DISABLED = true;
|
|
445
|
+
VIBEOS_API_TOKEN = "";
|
|
446
|
+
VIBEOS_API_BOOTSTRAP_TOKEN = "";
|
|
447
|
+
VIBEOS_API_ENABLED = false;
|
|
448
|
+
_apiClient = null;
|
|
449
|
+
_apiFallbackMode = false;
|
|
450
|
+
_apiFallbackSince = null;
|
|
451
|
+
persistBootstrapToken("");
|
|
452
|
+
persistPrimaryApiEnvState({ token: "", disabled: true });
|
|
453
|
+
resetApiConnection();
|
|
454
|
+
console.error("[vibeOS] API token invalidated and remote API disabled");
|
|
455
|
+
}
|
|
456
|
+
catch (e) {
|
|
457
|
+
console.error("[vibeOS] Failed to invalidate API token:", e.message);
|
|
458
|
+
}
|
|
459
|
+
}
|
|
386
460
|
export function setApiBootstrapToken(newToken) {
|
|
387
461
|
try {
|
|
462
|
+
VIBEOS_API_DISABLED = false;
|
|
388
463
|
VIBEOS_API_BOOTSTRAP_TOKEN = String(newToken || "").trim();
|
|
389
464
|
VIBEOS_API_ENABLED = process.env.VIBEOS_API_ENABLED !== "false" && (!!VIBEOS_API_TOKEN || !!VIBEOS_API_BOOTSTRAP_TOKEN);
|
|
465
|
+
persistPrimaryApiEnvState({ disabled: false });
|
|
390
466
|
persistBootstrapToken(VIBEOS_API_BOOTSTRAP_TOKEN);
|
|
391
467
|
console.error("[vibeOS] Alpha bootstrap token updated");
|
|
392
468
|
}
|
|
@@ -401,6 +477,8 @@ let _bootstrapExchangeInFlight = null;
|
|
|
401
477
|
let _bootstrapExchangeFailedAt = 0;
|
|
402
478
|
export async function ensureBootstrapExchange() {
|
|
403
479
|
syncApiTokenFromDisk();
|
|
480
|
+
if (VIBEOS_API_DISABLED)
|
|
481
|
+
return false;
|
|
404
482
|
if (VIBEOS_API_TOKEN)
|
|
405
483
|
return true;
|
|
406
484
|
if (!VIBEOS_API_BOOTSTRAP_TOKEN)
|
|
@@ -437,10 +515,26 @@ export async function ensureBootstrapExchange() {
|
|
|
437
515
|
return _bootstrapExchangeInFlight;
|
|
438
516
|
}
|
|
439
517
|
function syncApiTokenFromDisk() {
|
|
518
|
+
const diskDisabled = readApiDisabledFromDisk() || isTruthyFlag(process.env.VIBEOS_API_DISABLED);
|
|
440
519
|
const diskToken = readTokenFromDisk() || "";
|
|
441
520
|
const diskBootstrapToken = readBootstrapTokenFromDisk() || "";
|
|
442
|
-
const envToken = process.env.VIBEOS_API_TOKEN
|
|
521
|
+
const envToken = normalizeApiToken(process.env.VIBEOS_API_TOKEN, "");
|
|
522
|
+
if (diskDisabled) {
|
|
523
|
+
if (!VIBEOS_API_DISABLED || VIBEOS_API_TOKEN || VIBEOS_API_BOOTSTRAP_TOKEN || VIBEOS_API_ENABLED) {
|
|
524
|
+
VIBEOS_API_DISABLED = true;
|
|
525
|
+
VIBEOS_API_TOKEN = "";
|
|
526
|
+
VIBEOS_API_BOOTSTRAP_TOKEN = "";
|
|
527
|
+
VIBEOS_API_ENABLED = false;
|
|
528
|
+
_apiClient = null;
|
|
529
|
+
_apiFallbackMode = false;
|
|
530
|
+
_apiFallbackSince = null;
|
|
531
|
+
resetApiConnection();
|
|
532
|
+
console.error("[vibeOS] API token disabled from disk (alpha kill switch active)");
|
|
533
|
+
}
|
|
534
|
+
return;
|
|
535
|
+
}
|
|
443
536
|
if (diskToken && diskToken !== VIBEOS_API_TOKEN) {
|
|
537
|
+
VIBEOS_API_DISABLED = false;
|
|
444
538
|
VIBEOS_API_TOKEN = diskToken;
|
|
445
539
|
VIBEOS_API_ENABLED = process.env.VIBEOS_API_ENABLED !== "false" && (!!VIBEOS_API_TOKEN || !!VIBEOS_API_BOOTSTRAP_TOKEN);
|
|
446
540
|
_apiClient = null;
|
|
@@ -450,6 +544,7 @@ function syncApiTokenFromDisk() {
|
|
|
450
544
|
console.error("[vibeOS] API token synced from disk (disk is newer)");
|
|
451
545
|
}
|
|
452
546
|
else if (diskBootstrapToken && diskBootstrapToken !== VIBEOS_API_BOOTSTRAP_TOKEN) {
|
|
547
|
+
VIBEOS_API_DISABLED = false;
|
|
453
548
|
VIBEOS_API_BOOTSTRAP_TOKEN = diskBootstrapToken;
|
|
454
549
|
VIBEOS_API_ENABLED = process.env.VIBEOS_API_ENABLED !== "false" && (!!VIBEOS_API_TOKEN || !!VIBEOS_API_BOOTSTRAP_TOKEN);
|
|
455
550
|
_apiFallbackMode = false;
|
|
@@ -458,37 +553,18 @@ function syncApiTokenFromDisk() {
|
|
|
458
553
|
console.error("[vibeOS] Alpha bootstrap token synced from disk (disk is newer)");
|
|
459
554
|
}
|
|
460
555
|
else if (!diskToken && VIBEOS_API_TOKEN) {
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
if (existsSync(primaryPath)) {
|
|
464
|
-
let envContent = readFileSync(primaryPath, "utf8");
|
|
465
|
-
if (/^VIBEOS_API_TOKEN=/m.test(envContent)) {
|
|
466
|
-
envContent = envContent.replace(/^VIBEOS_API_TOKEN=.+$/m, `VIBEOS_API_TOKEN=${VIBEOS_API_TOKEN}`);
|
|
467
|
-
}
|
|
468
|
-
else {
|
|
469
|
-
envContent = envContent.trimEnd() + `\nVIBEOS_API_TOKEN=${VIBEOS_API_TOKEN}\n`;
|
|
470
|
-
}
|
|
471
|
-
writeFileSync(primaryPath, envContent, "utf8");
|
|
472
|
-
}
|
|
473
|
-
else {
|
|
474
|
-
const parentDir = _envPaths[0];
|
|
475
|
-
if (!existsSync(parentDir))
|
|
476
|
-
mkdirSync(parentDir, { recursive: true });
|
|
477
|
-
writeFileSync(primaryPath, `VIBEOS_API_TOKEN=${VIBEOS_API_TOKEN}\n`, "utf8");
|
|
478
|
-
}
|
|
479
|
-
console.error("[vibeOS] API token persisted to disk from memory (disk was empty)");
|
|
480
|
-
}
|
|
481
|
-
catch (diskErr) {
|
|
482
|
-
console.error("[vibeOS] Failed to persist API token to disk from sync:", diskErr.message);
|
|
483
|
-
}
|
|
556
|
+
persistPrimaryApiEnvState({ token: VIBEOS_API_TOKEN, disabled: false });
|
|
557
|
+
console.error("[vibeOS] API token persisted to disk from memory (disk was empty)");
|
|
484
558
|
VIBEOS_API_ENABLED = process.env.VIBEOS_API_ENABLED !== "false" && !!VIBEOS_API_TOKEN;
|
|
485
559
|
}
|
|
486
560
|
else if (envToken && !diskToken && !VIBEOS_API_TOKEN) {
|
|
561
|
+
VIBEOS_API_DISABLED = false;
|
|
487
562
|
VIBEOS_API_TOKEN = envToken;
|
|
488
563
|
VIBEOS_API_ENABLED = process.env.VIBEOS_API_ENABLED !== "false" && (!!VIBEOS_API_TOKEN || !!VIBEOS_API_BOOTSTRAP_TOKEN);
|
|
489
564
|
console.error("[vibeOS] API token loaded from VIBEOS_API_TOKEN env var");
|
|
490
565
|
}
|
|
491
566
|
else {
|
|
567
|
+
VIBEOS_API_DISABLED = false;
|
|
492
568
|
VIBEOS_API_TOKEN ||= EMBEDDED_API_TOKEN;
|
|
493
569
|
VIBEOS_API_ENABLED = process.env.VIBEOS_API_ENABLED !== "false" && (!!VIBEOS_API_TOKEN || !!VIBEOS_API_BOOTSTRAP_TOKEN);
|
|
494
570
|
}
|
package/src/lib/hooks/footer.js
CHANGED
|
@@ -9,6 +9,13 @@ import { saveReport } from "../reporting.js";
|
|
|
9
9
|
import { currentModel, currentTier, setCurrentModel, setCurrentTier, currentProjectFingerprint, currentProjectName, _modelLocked, _blackboxEnabled, _latestBlackboxState, reconcileStateFromLedger, safeJsonParse, loadBlackboxState } from "../state.js";
|
|
10
10
|
import { loadSessionSlot } from "../selection-manager.js";
|
|
11
11
|
import { remoteCall, VIBEOS_API_ENABLED } from "../api-client.js";
|
|
12
|
+
const IS_CLI_RUNTIME = Boolean(process.stdout?.isTTY || process.stderr?.isTTY || process.stdin?.isTTY);
|
|
13
|
+
const IS_TEST_RUNTIME = process.env.VIBEOS_MCP_PORT === "0" || process.env.NODE_ENV === "test" || process.env.CI === "true";
|
|
14
|
+
const FOOTER_DEBUG_STDERR = process.env.VIBEOS_DEBUG_FOOTER === "1" || (!IS_CLI_RUNTIME && !IS_TEST_RUNTIME);
|
|
15
|
+
function footerDebug(...args) {
|
|
16
|
+
if (FOOTER_DEBUG_STDERR)
|
|
17
|
+
console.error(...args);
|
|
18
|
+
}
|
|
12
19
|
function getVibeOSHome() {
|
|
13
20
|
return process.env.VIBEOS_HOME || join(process.env.HOME || "", ".claude");
|
|
14
21
|
}
|
|
@@ -38,9 +45,7 @@ async function apiAutoSelectMode(regime, stress) {
|
|
|
38
45
|
return res.mode;
|
|
39
46
|
}
|
|
40
47
|
}
|
|
41
|
-
catch (e) {
|
|
42
|
-
console.error("[vibeOS] apiAutoSelectMode error:", e.message);
|
|
43
|
-
}
|
|
48
|
+
catch (e) { footerDebug("[vibeOS] apiAutoSelectMode error:", e.message); }
|
|
44
49
|
const fallback = regimeToMode(regime, stress);
|
|
45
50
|
if (!_cachedAutoMode || _cachedAutoMode === "balanced")
|
|
46
51
|
_cachedAutoMode = fallback;
|
|
@@ -142,15 +147,15 @@ async function _appendFooter(input, output, directory) {
|
|
|
142
147
|
// Always prefer the live OpenCode model setting when available.
|
|
143
148
|
try {
|
|
144
149
|
const cfg = await client.config.get("model");
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
150
|
+
if (cfg) {
|
|
151
|
+
const cfgModel = String(cfg);
|
|
152
|
+
if (cfgModel !== currentModel) {
|
|
153
|
+
setCurrentModel(cfgModel);
|
|
154
|
+
setCurrentTier(classify(cfgModel));
|
|
155
|
+
footerDebug(`[vibeOS] client-detected model: ${currentModel} (tier=${currentTier})`);
|
|
156
|
+
}
|
|
151
157
|
}
|
|
152
158
|
}
|
|
153
|
-
}
|
|
154
159
|
catch { /* client.config may not be available */ }
|
|
155
160
|
try {
|
|
156
161
|
const messageID = input?.messageID ||
|
|
@@ -221,9 +226,7 @@ async function _appendFooter(input, output, directory) {
|
|
|
221
226
|
tags: ["auto", "cost"],
|
|
222
227
|
});
|
|
223
228
|
}
|
|
224
|
-
catch (e) {
|
|
225
|
-
console.error("[vibeOS] auto-report:", e.message);
|
|
226
|
-
}
|
|
229
|
+
catch (e) { footerDebug("[vibeOS] auto-report:", e.message); }
|
|
227
230
|
}
|
|
228
231
|
// Enforcement state tags for footer — dynamically adjusted by control vector
|
|
229
232
|
const selNowFooter = loadSelection();
|
|
@@ -325,7 +328,7 @@ async function _appendFooter(input, output, directory) {
|
|
|
325
328
|
}
|
|
326
329
|
}
|
|
327
330
|
catch (err) {
|
|
328
|
-
|
|
331
|
+
footerDebug(`[vibeOS] footer failed: ${err.message}`);
|
|
329
332
|
}
|
|
330
333
|
}
|
|
331
334
|
export { _appendFooter, scoreTaskQuality, readRewardSignals };
|
package/src/lib/trinity-tool.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// @ts-nocheck
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { LABEL_MODES, buildDeterministicTrinity, resolveExecutionIdentity } from "./pricing.js";
|
|
4
|
+
import { invalidateApiToken } from "./api-client.js";
|
|
4
5
|
export function createTrinityTool(deps) {
|
|
5
6
|
return {
|
|
6
7
|
description: "Control the vibeOS plugin and active model slot. " +
|
|
@@ -18,7 +19,7 @@ export function createTrinityTool(deps) {
|
|
|
18
19
|
"Use action='setup' to create a compatibility profile for first-time users. " +
|
|
19
20
|
"Use action='project' to show per-project analytics and optimization suggestions. " +
|
|
20
21
|
"Use action='patterns' to inspect learned project patterns or slot='clear' to clear them. " +
|
|
21
|
-
"Use action='guard' to ensure AGENTS.md and README.md exist and stay current. Use action='api-token' with token='<new_token>' to update the API token and re-enable remote control-vector " +
|
|
22
|
+
"Use action='guard' to ensure AGENTS.md and README.md exist and stay current. Use action='api-token' with token='<new_token>' to update the API token and re-enable remote control-vector, or token='invalidate' to disable the embedded alpha token " +
|
|
22
23
|
"Use action='api-bootstrap-token' with token='<new_token>' to store an alpha bootstrap token and exchange it for a normal API token on alpha builds. " +
|
|
23
24
|
"Call this when the user says things like 'switch to medium', 'use cheap model', 'disable plugin', 'trinity status'.",
|
|
24
25
|
args: {
|
|
@@ -726,7 +727,12 @@ export function createTrinityTool(deps) {
|
|
|
726
727
|
}
|
|
727
728
|
if (action === "api-token") {
|
|
728
729
|
if (!token)
|
|
729
|
-
return "Usage: trinity api-token <token>\nProvide a valid VIBEOS_API_TOKEN to enable remote control-vector computation.";
|
|
730
|
+
return "Usage: trinity api-token <token|invalidate>\nProvide a valid VIBEOS_API_TOKEN to enable remote control-vector computation, or 'invalidate' to disable it for alpha.";
|
|
731
|
+
const cleanToken = String(token).trim();
|
|
732
|
+
if (["invalidate", "disable", "clear", "revoke"].includes(cleanToken.toLowerCase())) {
|
|
733
|
+
invalidateApiToken();
|
|
734
|
+
return "[vibeOS] API token invalidated. Remote API disabled until a new token is set.";
|
|
735
|
+
}
|
|
730
736
|
deps.setApiToken(token);
|
|
731
737
|
return "[vibeOS] API token updated. Remote API re-enabled.";
|
|
732
738
|
}
|
|
@@ -1102,8 +1108,8 @@ export function createTrinityTool(deps) {
|
|
|
1102
1108
|
" trinity tdd on/off Toggle auto test skeleton creation",
|
|
1103
1109
|
" trinity setup Create a compatibility profile for new users",
|
|
1104
1110
|
" trinity guard Ensure AGENTS.md/README.md exist and are current",
|
|
1105
|
-
" trinity api-token
|
|
1106
|
-
" trinity api-token
|
|
1111
|
+
" trinity api-token <token|invalidate> Update or invalidate VIBEOS_API_TOKEN",
|
|
1112
|
+
" trinity api-token <token|invalidate> Update or invalidate VIBEOS_API_TOKEN",
|
|
1107
1113
|
" trinity flow Show flow violations this session",
|
|
1108
1114
|
"",
|
|
1109
1115
|
"DIAGNOSTICS:",
|