vibeoscore 1.0.2

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.
Files changed (46) hide show
  1. package/.env.example +5 -0
  2. package/README.md +29 -0
  3. package/client.js +257 -0
  4. package/client.ts +334 -0
  5. package/dashboard/dist/assets/index-BnPt1Fii.js +1 -0
  6. package/dashboard/dist/assets/index-CfH00tOL.css +1 -0
  7. package/dashboard/dist/index.html +3 -0
  8. package/lib/blackbox-rf.js +1099 -0
  9. package/lib/blackbox.js +137 -0
  10. package/lib/compression.js +119 -0
  11. package/lib/db.js +106 -0
  12. package/lib/db.ts +113 -0
  13. package/lib/delegation.js +137 -0
  14. package/lib/meta-controller.js +418 -0
  15. package/lib/meta-controller.mjs +499 -0
  16. package/lib/patterns.js +150 -0
  17. package/lib/resolution-tracker.js +486 -0
  18. package/lib/stress.js +84 -0
  19. package/lib/tdd.js +218 -0
  20. package/lib/tier-routing.js +48 -0
  21. package/mcp-server.js +370 -0
  22. package/mcp-server.ts +364 -0
  23. package/middleware/auth.js +75 -0
  24. package/middleware/auth.ts +87 -0
  25. package/middleware/usage-logging.js +29 -0
  26. package/middleware/usage-logging.ts +41 -0
  27. package/nginx-vibetheog-api.conf +64 -0
  28. package/package.json +66 -0
  29. package/routes/admin.js +93 -0
  30. package/routes/admin.ts +107 -0
  31. package/routes/blackbox.js +463 -0
  32. package/routes/compression.js +12 -0
  33. package/routes/delegation.js +30 -0
  34. package/routes/patterns.js +53 -0
  35. package/routes/pricing.js +62 -0
  36. package/routes/stress.js +30 -0
  37. package/routes/tdd.js +68 -0
  38. package/routes/tier-routing.js +31 -0
  39. package/scripts/dashboard-server.mjs +246 -0
  40. package/scripts/deploy-zero-downtime.sh +77 -0
  41. package/scripts/deploy.sh +68 -0
  42. package/scripts/release.mjs +30 -0
  43. package/scripts/seed-master-token.js +29 -0
  44. package/scripts/start-all.mjs +34 -0
  45. package/server.js +88 -0
  46. package/vibeos-api.service +19 -0
package/.env.example ADDED
@@ -0,0 +1,5 @@
1
+ VIBEOS_API_MASTER_KEY=change_this_to_a_secure_random_string
2
+ VIBEOS_API_DB_PATH=./data/vibeos-api.db
3
+ PORT=3000
4
+ HOST=0.0.0.0
5
+ NODE_ENV=production
package/README.md ADDED
@@ -0,0 +1,29 @@
1
+ # vibeOScore
2
+
3
+ ## Tech Stack
4
+
5
+ `typescript`, `javascript`
6
+
7
+ ## Features
8
+
9
+ (Feature list maintained by vibeOS — run `trinity guard` to refresh)
10
+
11
+ ## Getting Started
12
+
13
+ ```bash
14
+ # Clone and install dependencies
15
+ ```
16
+
17
+ ## API Token (Alpha)
18
+
19
+ This is the vibeOScore API token. It can be revoked and will be replaced with auto-generated tokens in a future release.
20
+
21
+ ```
22
+ VIBEOS_API_TOKEN=vos_59d73aa4b7838a7ca9dafe957993177b5629c7954091db3350b4150882ff7064
23
+ ```
24
+
25
+ Set this as an environment variable or add it to `~/.claude/.env.production`:
26
+
27
+ ```bash
28
+ export VIBEOS_API_TOKEN=vos_59d73aa4b7838a7ca9dafe957993177b5629c7954091db3350b4150882ff7064
29
+ ```
package/client.js ADDED
@@ -0,0 +1,257 @@
1
+ // SPDX-License-Identifier: MIT
2
+ // SPDX-FileCopyrightText: 2026 vibeOS <https://github.com/DrunkkToys/vibeOS>
3
+ const DEFAULT_API_URL = "https://api.vibetheog.com";
4
+ const REQUEST_TIMEOUT = 10000;
5
+ const MAX_RETRIES = 3;
6
+ const BASE_RETRY_DELAY = 1000;
7
+ class VibeOSApiClient {
8
+ baseUrl;
9
+ apiToken;
10
+ masterKey;
11
+ timeout;
12
+ fallbackMode;
13
+ fallbackStubs;
14
+ constructor(options = {}) {
15
+ this.baseUrl = options.baseUrl || process.env.VIBEOS_API_URL || DEFAULT_API_URL;
16
+ this.apiToken = options.apiToken || process.env.VIBEOS_API_TOKEN || null;
17
+ this.masterKey = options.masterKey || process.env.VIBEOS_API_MASTER_KEY || null;
18
+ this.timeout = options.timeout || REQUEST_TIMEOUT;
19
+ this.fallbackMode = false;
20
+ this.fallbackStubs = options.fallbackStubs || null;
21
+ }
22
+ async request(path, body = null, isAdmin = false) {
23
+ if (!this.apiToken && !isAdmin) {
24
+ throw new Error("VIBEOS_API_TOKEN is not set");
25
+ }
26
+ const url = this.baseUrl + path;
27
+ const headers = {
28
+ "Content-Type": "application/json",
29
+ Authorization: "Bearer " + (isAdmin ? this.masterKey : this.apiToken),
30
+ };
31
+ let lastError = null;
32
+ let attempt = 0;
33
+ while (attempt <= MAX_RETRIES) {
34
+ if (attempt > 0) {
35
+ const delay = BASE_RETRY_DELAY * Math.pow(2, attempt - 1);
36
+ await new Promise(r => setTimeout(r, delay));
37
+ }
38
+ attempt++;
39
+ try {
40
+ const controller = new AbortController();
41
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
42
+ const res = await fetch(url, {
43
+ method: body ? "POST" : "GET",
44
+ headers,
45
+ body: body ? JSON.stringify(body) : null,
46
+ signal: controller.signal,
47
+ });
48
+ clearTimeout(timeoutId);
49
+ if (res.status === 401 || res.status === 403) {
50
+ const errorBody = await res.json().catch(() => ({}));
51
+ this.fallbackMode = true;
52
+ throw new VibeOSAuthError(errorBody.message || "Authentication failed", res.status, errorBody.code);
53
+ }
54
+ if (!res.ok) {
55
+ const errorBody = await res.json().catch(() => ({}));
56
+ if (res.status >= 500 && attempt <= MAX_RETRIES) {
57
+ lastError = new Error("API error " + res.status + ": " + (errorBody.error || res.statusText));
58
+ continue;
59
+ }
60
+ throw new Error("API error " + res.status + ": " + (errorBody.error || res.statusText));
61
+ }
62
+ this.fallbackMode = false;
63
+ return res.json();
64
+ }
65
+ catch (err) {
66
+ if (err instanceof VibeOSAuthError)
67
+ throw err;
68
+ const error = err;
69
+ if (error.name === "AbortError") {
70
+ if (attempt <= MAX_RETRIES) {
71
+ lastError = new VibeOSTimeoutError("Request to " + url + " timed out after " + this.timeout + "ms");
72
+ continue;
73
+ }
74
+ this.fallbackMode = true;
75
+ throw new VibeOSTimeoutError("Request to " + url + " timed out after " + this.timeout + "ms");
76
+ }
77
+ lastError = err;
78
+ if (attempt <= MAX_RETRIES && error.message && (error.message.includes("fetch") || error.message.includes("network") || error.message.includes("ECONNREFUSED"))) {
79
+ continue;
80
+ }
81
+ }
82
+ }
83
+ this.fallbackMode = true;
84
+ throw new VibeOSNetworkError("Failed to reach API after " + MAX_RETRIES + " retries: " + (lastError ? lastError.message : "unknown error"));
85
+ }
86
+ async delegateCheck(tool, tier, model, prompt, dynamicCache = {}) {
87
+ return this.request("/api/v1/delegate/check", { tool, tier, model, prompt, dynamic_cache: dynamicCache });
88
+ }
89
+ async delegateSoftQuota(tool, currentCount, limit = 5) {
90
+ return this.request("/api/v1/delegate/soft-quota", { tool, current_count: currentCount, limit });
91
+ }
92
+ async delegateCost(model, dynamicCache = {}) {
93
+ return this.request("/api/v1/delegation/cost", { model, dynamic_cache: dynamicCache });
94
+ }
95
+ async routeModel(prompt, currentTier, trinityCheap, trinityMedium, learnedExploratory = [], stressScore = 0) {
96
+ return this.request("/api/v1/route/model", {
97
+ prompt,
98
+ current_tier: currentTier,
99
+ trinity_cheap: trinityCheap,
100
+ trinity_medium: trinityMedium,
101
+ learned_exploratory: learnedExploratory,
102
+ stress_score: stressScore,
103
+ });
104
+ }
105
+ async classifyTier(model, customRegex = null) {
106
+ return this.request("/api/v1/tier/classify", { model, custom_regex: customRegex });
107
+ }
108
+ async isExploratory(prompt, learnedExploratory = []) {
109
+ return this.request("/api/v1/tier/exploratory", { prompt, learned_exploratory: learnedExploratory });
110
+ }
111
+ async scoreStress(text) {
112
+ return this.request("/api/v1/stress/score", { text });
113
+ }
114
+ async stressLevel(score) {
115
+ return this.request("/api/v1/stress/level", { score });
116
+ }
117
+ async blackboxAnalyze(sessionId, entry) {
118
+ return this.request("/api/v1/blackbox/analyze", {
119
+ session_id: sessionId,
120
+ project_id: entry.project_id || null,
121
+ user_text: entry.userText || "",
122
+ features: entry.features || {},
123
+ action: entry.action || "explore",
124
+ entropy: entry.entropy ?? 1.0,
125
+ uncertainty: entry.uncertainty ?? 50,
126
+ embedding: entry.embedding || null,
127
+ });
128
+ }
129
+ async blackboxState(sessionId) {
130
+ return this.request("/api/v1/blackbox/state", { session_id: sessionId });
131
+ }
132
+ async blackboxReset(sessionId) {
133
+ return this.request("/api/v1/blackbox/reset", { session_id: sessionId });
134
+ }
135
+ async blackboxOutcome(sessionId, outcome) {
136
+ return this.request("/api/v1/blackbox/outcome", { session_id: sessionId, outcome });
137
+ }
138
+ async blackboxCalibrate(projectId) {
139
+ return this.request("/api/v1/blackbox/calibrate", { project_id: projectId || "global" });
140
+ }
141
+ async blackboxCalibration(projectId) {
142
+ return this.request("/api/v1/blackbox/calibration?project_id=" + (projectId || "global"), null);
143
+ }
144
+ async blackboxControlVector(state, action, optimizationMode) {
145
+ return this.request("/api/v1/blackbox/control-vector", { ...state, action, optimization_mode: optimizationMode });
146
+ }
147
+ async blackboxSelectMode(subRegime, stressMultiplier) {
148
+ return this.request("/api/v1/blackbox/select-mode", { sub_regime: subRegime, stress_multiplier: stressMultiplier });
149
+ }
150
+ async tddExports(sourceContent, ext) {
151
+ return this.request("/api/v1/tdd/exports", { source_content: sourceContent, ext });
152
+ }
153
+ async tddParams(sourceContent, funcName) {
154
+ return this.request("/api/v1/tdd/params", { source_content: sourceContent, func_name: funcName });
155
+ }
156
+ async tddInferType(paramName, defaultValue) {
157
+ return this.request("/api/v1/tdd/infer-type", { param_name: paramName, default_value: defaultValue });
158
+ }
159
+ async tddSkeleton(language, fileName, exports, options = {}) {
160
+ return this.request("/api/v1/tdd/skeleton", { language, file_name: fileName, exports, options });
161
+ }
162
+ async patternsObserve(sessionId, toolName, input, output, directory) {
163
+ return this.request("/api/v1/patterns/observe", {
164
+ session_id: sessionId,
165
+ tool_name: toolName,
166
+ input,
167
+ output,
168
+ directory,
169
+ });
170
+ }
171
+ async patternsRecord(sessionId, kind, key, summary, meta = {}) {
172
+ return this.request("/api/v1/patterns/record", {
173
+ session_id: sessionId,
174
+ kind,
175
+ key,
176
+ summary,
177
+ meta,
178
+ });
179
+ }
180
+ async patternsQuery(sessionId, kind = null) {
181
+ return this.request("/api/v1/patterns/query?kind=" + (kind || ""), null);
182
+ }
183
+ async patternsExploratoryWords(sessionId) {
184
+ return this.request("/api/v1/patterns/exploratory-words", null);
185
+ }
186
+ async patternsClear(sessionId) {
187
+ return this.request("/api/v1/patterns/clear", { session_id: sessionId });
188
+ }
189
+ async pricingFetch(openrouterKey, force = false) {
190
+ return this.request("/api/v1/pricing/fetch", { openrouter_key: openrouterKey, force });
191
+ }
192
+ async pricingLookup(model) {
193
+ return this.request("/api/v1/pricing/lookup", { model });
194
+ }
195
+ async pricingStatic() {
196
+ return this.request("/api/v1/pricing/static", null);
197
+ }
198
+ async compressContext(text, threshold = 2000) {
199
+ return this.request("/api/v1/compress/context", { text, threshold });
200
+ }
201
+ async adminCreateSeat(name, email) {
202
+ return this.request("/admin/seats", { name, email }, true);
203
+ }
204
+ async adminCreateSeatWithToken(name, email, tokenLabel = null) {
205
+ return this.request("/admin/seats", { name, email, with_token: tokenLabel || true }, true);
206
+ }
207
+ async adminListSeats() {
208
+ return this.request("/admin/seats", null, true);
209
+ }
210
+ async adminUpdateSeat(seatId, status) {
211
+ return this.request("/admin/seats/" + seatId, { status }, true);
212
+ }
213
+ async adminCreateToken(seatId, label, expiresAt) {
214
+ return this.request("/admin/tokens", { seat_id: seatId, label, expires_at: expiresAt }, true);
215
+ }
216
+ async adminListTokens() {
217
+ return this.request("/admin/tokens", null, true);
218
+ }
219
+ async adminUpdateToken(tokenId, status) {
220
+ return this.request("/admin/tokens/" + tokenId, { status }, true);
221
+ }
222
+ async adminDeleteToken(tokenId) {
223
+ return this.request("/admin/tokens/" + tokenId, null, true);
224
+ }
225
+ async adminUsage(days = 30) {
226
+ return this.request("/admin/usage?days=" + days, null, true);
227
+ }
228
+ async health() {
229
+ return this.request("/health", null, false);
230
+ }
231
+ isFallback() {
232
+ return this.fallbackMode;
233
+ }
234
+ }
235
+ class VibeOSAuthError extends Error {
236
+ statusCode;
237
+ code;
238
+ constructor(message, statusCode, code) {
239
+ super(message);
240
+ this.name = "VibeOSAuthError";
241
+ this.statusCode = statusCode;
242
+ this.code = code;
243
+ }
244
+ }
245
+ class VibeOSTimeoutError extends Error {
246
+ constructor(message) {
247
+ super(message);
248
+ this.name = "VibeOSTimeoutError";
249
+ }
250
+ }
251
+ class VibeOSNetworkError extends Error {
252
+ constructor(message) {
253
+ super(message);
254
+ this.name = "VibeOSNetworkError";
255
+ }
256
+ }
257
+ export { VibeOSApiClient, VibeOSAuthError, VibeOSTimeoutError, VibeOSNetworkError };
package/client.ts ADDED
@@ -0,0 +1,334 @@
1
+ // SPDX-License-Identifier: MIT
2
+ // SPDX-FileCopyrightText: 2026 vibeOS <https://github.com/DrunkkToys/vibeOS>
3
+
4
+ const DEFAULT_API_URL = "https://api.vibetheog.com"
5
+ const REQUEST_TIMEOUT = 10000
6
+ const MAX_RETRIES = 3
7
+ const BASE_RETRY_DELAY = 1000
8
+
9
+ type ApiClientOptions = {
10
+ baseUrl?: string
11
+ apiToken?: string
12
+ masterKey?: string
13
+ timeout?: number
14
+ fallbackStubs?: unknown
15
+ }
16
+
17
+ type BlackboxEntry = {
18
+ project_id?: string | null
19
+ userText?: string
20
+ features?: Record<string, unknown>
21
+ action?: string
22
+ entropy?: number
23
+ uncertainty?: number
24
+ embedding?: unknown
25
+ }
26
+
27
+ class VibeOSApiClient {
28
+ baseUrl: string
29
+ apiToken: string | null
30
+ masterKey: string | null
31
+ timeout: number
32
+ fallbackMode: boolean
33
+ fallbackStubs: unknown
34
+
35
+ constructor(options: ApiClientOptions = {}) {
36
+ this.baseUrl = options.baseUrl || process.env.VIBEOS_API_URL || DEFAULT_API_URL
37
+ this.apiToken = options.apiToken || process.env.VIBEOS_API_TOKEN || null
38
+ this.masterKey = options.masterKey || process.env.VIBEOS_API_MASTER_KEY || null
39
+ this.timeout = options.timeout || REQUEST_TIMEOUT
40
+ this.fallbackMode = false
41
+ this.fallbackStubs = options.fallbackStubs || null
42
+ }
43
+
44
+ async request(path: string, body: Record<string, unknown> | null = null, isAdmin = false): Promise<unknown> {
45
+ if (!this.apiToken && !isAdmin) {
46
+ throw new Error("VIBEOS_API_TOKEN is not set")
47
+ }
48
+
49
+ const url = this.baseUrl + path
50
+ const headers: Record<string, string> = {
51
+ "Content-Type": "application/json",
52
+ Authorization: "Bearer " + (isAdmin ? this.masterKey : this.apiToken),
53
+ }
54
+
55
+ let lastError: Error | null = null
56
+ let attempt = 0
57
+
58
+ while (attempt <= MAX_RETRIES) {
59
+ if (attempt > 0) {
60
+ const delay = BASE_RETRY_DELAY * Math.pow(2, attempt - 1)
61
+ await new Promise(r => setTimeout(r, delay))
62
+ }
63
+ attempt++
64
+
65
+ try {
66
+ const controller = new AbortController()
67
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout)
68
+
69
+ const res = await fetch(url, {
70
+ method: body ? "POST" : "GET",
71
+ headers,
72
+ body: body ? JSON.stringify(body) : null,
73
+ signal: controller.signal,
74
+ })
75
+
76
+ clearTimeout(timeoutId)
77
+
78
+ if (res.status === 401 || res.status === 403) {
79
+ const errorBody = await res.json().catch(() => ({})) as { message?: string; code?: string }
80
+ this.fallbackMode = true
81
+ throw new VibeOSAuthError(errorBody.message || "Authentication failed", res.status, errorBody.code)
82
+ }
83
+
84
+ if (!res.ok) {
85
+ const errorBody = await res.json().catch(() => ({})) as { error?: string }
86
+ if (res.status >= 500 && attempt <= MAX_RETRIES) {
87
+ lastError = new Error("API error " + res.status + ": " + (errorBody.error || res.statusText))
88
+ continue
89
+ }
90
+ throw new Error("API error " + res.status + ": " + (errorBody.error || res.statusText))
91
+ }
92
+
93
+ this.fallbackMode = false
94
+ return res.json()
95
+ } catch (err: unknown) {
96
+ if (err instanceof VibeOSAuthError) throw err
97
+ const error = err as { name?: string; message?: string }
98
+ if (error.name === "AbortError") {
99
+ if (attempt <= MAX_RETRIES) {
100
+ lastError = new VibeOSTimeoutError("Request to " + url + " timed out after " + this.timeout + "ms")
101
+ continue
102
+ }
103
+ this.fallbackMode = true
104
+ throw new VibeOSTimeoutError("Request to " + url + " timed out after " + this.timeout + "ms")
105
+ }
106
+ lastError = err as Error
107
+ if (attempt <= MAX_RETRIES && error.message && (
108
+ error.message.includes("fetch") || error.message.includes("network") || error.message.includes("ECONNREFUSED")
109
+ )) {
110
+ continue
111
+ }
112
+ }
113
+ }
114
+
115
+ this.fallbackMode = true
116
+ throw new VibeOSNetworkError("Failed to reach API after " + MAX_RETRIES + " retries: " + (lastError ? lastError.message : "unknown error"))
117
+ }
118
+
119
+ async delegateCheck(tool: string, tier: string, model: string, prompt: string, dynamicCache: Record<string, unknown> = {}): Promise<unknown> {
120
+ return this.request("/api/v1/delegate/check", { tool, tier, model, prompt, dynamic_cache: dynamicCache })
121
+ }
122
+
123
+ async delegateSoftQuota(tool: string, currentCount: number, limit = 5): Promise<unknown> {
124
+ return this.request("/api/v1/delegate/soft-quota", { tool, current_count: currentCount, limit })
125
+ }
126
+
127
+ async delegateCost(model: string, dynamicCache: Record<string, unknown> = {}): Promise<unknown> {
128
+ return this.request("/api/v1/delegation/cost", { model, dynamic_cache: dynamicCache })
129
+ }
130
+
131
+ async routeModel(prompt: string, currentTier: string, trinityCheap: string, trinityMedium: string, learnedExploratory: string[] = [], stressScore = 0): Promise<unknown> {
132
+ return this.request("/api/v1/route/model", {
133
+ prompt,
134
+ current_tier: currentTier,
135
+ trinity_cheap: trinityCheap,
136
+ trinity_medium: trinityMedium,
137
+ learned_exploratory: learnedExploratory,
138
+ stress_score: stressScore,
139
+ })
140
+ }
141
+
142
+ async classifyTier(model: string, customRegex: string | null = null): Promise<unknown> {
143
+ return this.request("/api/v1/tier/classify", { model, custom_regex: customRegex })
144
+ }
145
+
146
+ async isExploratory(prompt: string, learnedExploratory: string[] = []): Promise<unknown> {
147
+ return this.request("/api/v1/tier/exploratory", { prompt, learned_exploratory: learnedExploratory })
148
+ }
149
+
150
+ async scoreStress(text: string): Promise<unknown> {
151
+ return this.request("/api/v1/stress/score", { text })
152
+ }
153
+
154
+ async stressLevel(score: number): Promise<unknown> {
155
+ return this.request("/api/v1/stress/level", { score })
156
+ }
157
+
158
+ async blackboxAnalyze(sessionId: string, entry: BlackboxEntry): Promise<unknown> {
159
+ return this.request("/api/v1/blackbox/analyze", {
160
+ session_id: sessionId,
161
+ project_id: entry.project_id || null,
162
+ user_text: entry.userText || "",
163
+ features: entry.features || {},
164
+ action: entry.action || "explore",
165
+ entropy: entry.entropy ?? 1.0,
166
+ uncertainty: entry.uncertainty ?? 50,
167
+ embedding: entry.embedding || null,
168
+ })
169
+ }
170
+
171
+ async blackboxState(sessionId: string): Promise<unknown> {
172
+ return this.request("/api/v1/blackbox/state", { session_id: sessionId })
173
+ }
174
+
175
+ async blackboxReset(sessionId: string): Promise<unknown> {
176
+ return this.request("/api/v1/blackbox/reset", { session_id: sessionId })
177
+ }
178
+
179
+ async blackboxOutcome(sessionId: string, outcome: unknown): Promise<unknown> {
180
+ return this.request("/api/v1/blackbox/outcome", { session_id: sessionId, outcome })
181
+ }
182
+
183
+ async blackboxCalibrate(projectId: string): Promise<unknown> {
184
+ return this.request("/api/v1/blackbox/calibrate", { project_id: projectId || "global" })
185
+ }
186
+
187
+ async blackboxCalibration(projectId: string): Promise<unknown> {
188
+ return this.request("/api/v1/blackbox/calibration?project_id=" + (projectId || "global"), null)
189
+ }
190
+
191
+ async blackboxControlVector(state: unknown, action: unknown, optimizationMode: string): Promise<unknown> {
192
+ return this.request("/api/v1/blackbox/control-vector", { ...(state as Record<string, unknown>), action, optimization_mode: optimizationMode })
193
+ }
194
+
195
+ async blackboxSelectMode(subRegime: string, stressMultiplier: number): Promise<unknown> {
196
+ return this.request("/api/v1/blackbox/select-mode", { sub_regime: subRegime, stress_multiplier: stressMultiplier })
197
+ }
198
+
199
+ async tddExports(sourceContent: string, ext: string): Promise<unknown> {
200
+ return this.request("/api/v1/tdd/exports", { source_content: sourceContent, ext })
201
+ }
202
+
203
+ async tddParams(sourceContent: string, funcName: string): Promise<unknown> {
204
+ return this.request("/api/v1/tdd/params", { source_content: sourceContent, func_name: funcName })
205
+ }
206
+
207
+ async tddInferType(paramName: string, defaultValue: unknown): Promise<unknown> {
208
+ return this.request("/api/v1/tdd/infer-type", { param_name: paramName, default_value: defaultValue })
209
+ }
210
+
211
+ async tddSkeleton(language: string, fileName: string, exports: unknown[], options: Record<string, unknown> = {}): Promise<unknown> {
212
+ return this.request("/api/v1/tdd/skeleton", { language, file_name: fileName, exports, options })
213
+ }
214
+
215
+ async patternsObserve(sessionId: string, toolName: string, input: unknown, output: unknown, directory: string): Promise<unknown> {
216
+ return this.request("/api/v1/patterns/observe", {
217
+ session_id: sessionId,
218
+ tool_name: toolName,
219
+ input,
220
+ output,
221
+ directory,
222
+ })
223
+ }
224
+
225
+ async patternsRecord(sessionId: string, kind: string, key: string, summary: string, meta: Record<string, unknown> = {}): Promise<unknown> {
226
+ return this.request("/api/v1/patterns/record", {
227
+ session_id: sessionId,
228
+ kind,
229
+ key,
230
+ summary,
231
+ meta,
232
+ })
233
+ }
234
+
235
+ async patternsQuery(sessionId: string, kind: string | null = null): Promise<unknown> {
236
+ return this.request("/api/v1/patterns/query?kind=" + (kind || ""), null)
237
+ }
238
+
239
+ async patternsExploratoryWords(sessionId: string): Promise<unknown> {
240
+ return this.request("/api/v1/patterns/exploratory-words", null)
241
+ }
242
+
243
+ async patternsClear(sessionId: string): Promise<unknown> {
244
+ return this.request("/api/v1/patterns/clear", { session_id: sessionId })
245
+ }
246
+
247
+ async pricingFetch(openrouterKey: string, force = false): Promise<unknown> {
248
+ return this.request("/api/v1/pricing/fetch", { openrouter_key: openrouterKey, force })
249
+ }
250
+
251
+ async pricingLookup(model: string): Promise<unknown> {
252
+ return this.request("/api/v1/pricing/lookup", { model })
253
+ }
254
+
255
+ async pricingStatic(): Promise<unknown> {
256
+ return this.request("/api/v1/pricing/static", null)
257
+ }
258
+
259
+ async compressContext(text: string, threshold = 2000): Promise<unknown> {
260
+ return this.request("/api/v1/compress/context", { text, threshold })
261
+ }
262
+
263
+ async adminCreateSeat(name: string, email: string): Promise<unknown> {
264
+ return this.request("/admin/seats", { name, email }, true)
265
+ }
266
+
267
+ async adminCreateSeatWithToken(name: string, email: string, tokenLabel: string | null = null): Promise<unknown> {
268
+ return this.request("/admin/seats", { name, email, with_token: tokenLabel || true }, true)
269
+ }
270
+
271
+ async adminListSeats(): Promise<unknown> {
272
+ return this.request("/admin/seats", null, true)
273
+ }
274
+
275
+ async adminUpdateSeat(seatId: string, status: string): Promise<unknown> {
276
+ return this.request("/admin/seats/" + seatId, { status }, true)
277
+ }
278
+
279
+ async adminCreateToken(seatId: string, label: string, expiresAt: string): Promise<unknown> {
280
+ return this.request("/admin/tokens", { seat_id: seatId, label, expires_at: expiresAt }, true)
281
+ }
282
+
283
+ async adminListTokens(): Promise<unknown> {
284
+ return this.request("/admin/tokens", null, true)
285
+ }
286
+
287
+ async adminUpdateToken(tokenId: string, status: string): Promise<unknown> {
288
+ return this.request("/admin/tokens/" + tokenId, { status }, true)
289
+ }
290
+
291
+ async adminDeleteToken(tokenId: string): Promise<unknown> {
292
+ return this.request("/admin/tokens/" + tokenId, null, true)
293
+ }
294
+
295
+ async adminUsage(days = 30): Promise<unknown> {
296
+ return this.request("/admin/usage?days=" + days, null, true)
297
+ }
298
+
299
+ async health(): Promise<unknown> {
300
+ return this.request("/health", null, false)
301
+ }
302
+
303
+ isFallback(): boolean {
304
+ return this.fallbackMode
305
+ }
306
+ }
307
+
308
+ class VibeOSAuthError extends Error {
309
+ statusCode: number
310
+ code?: string
311
+
312
+ constructor(message: string, statusCode: number, code?: string) {
313
+ super(message)
314
+ this.name = "VibeOSAuthError"
315
+ this.statusCode = statusCode
316
+ this.code = code
317
+ }
318
+ }
319
+
320
+ class VibeOSTimeoutError extends Error {
321
+ constructor(message: string) {
322
+ super(message)
323
+ this.name = "VibeOSTimeoutError"
324
+ }
325
+ }
326
+
327
+ class VibeOSNetworkError extends Error {
328
+ constructor(message: string) {
329
+ super(message)
330
+ this.name = "VibeOSNetworkError"
331
+ }
332
+ }
333
+
334
+ export { VibeOSApiClient, VibeOSAuthError, VibeOSTimeoutError, VibeOSNetworkError }