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.
- package/.env.example +5 -0
- package/README.md +29 -0
- package/client.js +257 -0
- package/client.ts +334 -0
- package/dashboard/dist/assets/index-BnPt1Fii.js +1 -0
- package/dashboard/dist/assets/index-CfH00tOL.css +1 -0
- package/dashboard/dist/index.html +3 -0
- package/lib/blackbox-rf.js +1099 -0
- package/lib/blackbox.js +137 -0
- package/lib/compression.js +119 -0
- package/lib/db.js +106 -0
- package/lib/db.ts +113 -0
- package/lib/delegation.js +137 -0
- package/lib/meta-controller.js +418 -0
- package/lib/meta-controller.mjs +499 -0
- package/lib/patterns.js +150 -0
- package/lib/resolution-tracker.js +486 -0
- package/lib/stress.js +84 -0
- package/lib/tdd.js +218 -0
- package/lib/tier-routing.js +48 -0
- package/mcp-server.js +370 -0
- package/mcp-server.ts +364 -0
- package/middleware/auth.js +75 -0
- package/middleware/auth.ts +87 -0
- package/middleware/usage-logging.js +29 -0
- package/middleware/usage-logging.ts +41 -0
- package/nginx-vibetheog-api.conf +64 -0
- package/package.json +66 -0
- package/routes/admin.js +93 -0
- package/routes/admin.ts +107 -0
- package/routes/blackbox.js +463 -0
- package/routes/compression.js +12 -0
- package/routes/delegation.js +30 -0
- package/routes/patterns.js +53 -0
- package/routes/pricing.js +62 -0
- package/routes/stress.js +30 -0
- package/routes/tdd.js +68 -0
- package/routes/tier-routing.js +31 -0
- package/scripts/dashboard-server.mjs +246 -0
- package/scripts/deploy-zero-downtime.sh +77 -0
- package/scripts/deploy.sh +68 -0
- package/scripts/release.mjs +30 -0
- package/scripts/seed-master-token.js +29 -0
- package/scripts/start-all.mjs +34 -0
- package/server.js +88 -0
- package/vibeos-api.service +19 -0
package/package.json
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "vibeoscore",
|
|
3
|
+
"version": "1.0.2",
|
|
4
|
+
"description": "vibeOS backend core: API server, MCP server, web dashboard, and API client",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"exports": {
|
|
7
|
+
"./client": "./client.js",
|
|
8
|
+
"./mcp-server": "./mcp-server.js",
|
|
9
|
+
"./server": "./server.js"
|
|
10
|
+
},
|
|
11
|
+
"scripts": {
|
|
12
|
+
"start": "node server.js",
|
|
13
|
+
"start:all": "node scripts/start-all.mjs",
|
|
14
|
+
"dev": "node --watch server.js",
|
|
15
|
+
"seed": "node scripts/seed-master-token.js",
|
|
16
|
+
"deploy": "bash scripts/deploy.sh",
|
|
17
|
+
"release": "node scripts/release.mjs",
|
|
18
|
+
"release:patch": "node scripts/release.mjs patch --yes",
|
|
19
|
+
"release:minor": "node scripts/release.mjs minor --yes",
|
|
20
|
+
"release:major": "node scripts/release.mjs major --yes",
|
|
21
|
+
"build:dashboard": "cd dashboard && npm install && npm run build",
|
|
22
|
+
"dev:dashboard": "cd dashboard && npm run dev",
|
|
23
|
+
"dashboard:serve": "node scripts/dashboard-server.mjs",
|
|
24
|
+
"typecheck": "tsc --noEmit",
|
|
25
|
+
"test": "node --test tests/*.test.js tests/*.test.mjs"
|
|
26
|
+
},
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"@fastify/cors": "^11.2.0",
|
|
29
|
+
"better-sqlite3": "^11.7.0",
|
|
30
|
+
"fastify": "^5.2.0"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@types/node": "^22.15.30",
|
|
34
|
+
"typescript": "^5.9.3"
|
|
35
|
+
},
|
|
36
|
+
"files": [
|
|
37
|
+
"client.js",
|
|
38
|
+
"client.ts",
|
|
39
|
+
"mcp-server.js",
|
|
40
|
+
"mcp-server.ts",
|
|
41
|
+
"server.js",
|
|
42
|
+
"lib/",
|
|
43
|
+
"middleware/",
|
|
44
|
+
"routes/",
|
|
45
|
+
"dashboard/dist/",
|
|
46
|
+
"scripts/",
|
|
47
|
+
"nginx-vibetheog-api.conf",
|
|
48
|
+
"vibeos-api.service",
|
|
49
|
+
".env.example"
|
|
50
|
+
],
|
|
51
|
+
"keywords": [
|
|
52
|
+
"vibeos",
|
|
53
|
+
"api",
|
|
54
|
+
"opencode",
|
|
55
|
+
"mcp"
|
|
56
|
+
],
|
|
57
|
+
"author": "vibeOS",
|
|
58
|
+
"license": "MIT",
|
|
59
|
+
"repository": {
|
|
60
|
+
"type": "git",
|
|
61
|
+
"url": "git+https://github.com/DrunkkToys/vibeOScore.git"
|
|
62
|
+
},
|
|
63
|
+
"engines": {
|
|
64
|
+
"node": ">=18"
|
|
65
|
+
}
|
|
66
|
+
}
|
package/routes/admin.js
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { getDb } from "../lib/db.js";
|
|
2
|
+
import { randomBytes } from "node:crypto";
|
|
3
|
+
function generateToken() {
|
|
4
|
+
return "vos_" + randomBytes(32).toString("hex");
|
|
5
|
+
}
|
|
6
|
+
export async function adminRoutes(fastify) {
|
|
7
|
+
fastify.post("/admin/seats", async (request, reply) => {
|
|
8
|
+
const { name, email } = request.body || {};
|
|
9
|
+
if (!name) {
|
|
10
|
+
return reply.code(400).send({ error: "name is required" });
|
|
11
|
+
}
|
|
12
|
+
const db = getDb();
|
|
13
|
+
const result = db.prepare("INSERT INTO seats (name, email) VALUES (?, ?)").run(name, email || null);
|
|
14
|
+
const seat = db.prepare("SELECT * FROM seats WHERE id = ?").get(result.lastInsertRowid);
|
|
15
|
+
return { ok: true, seat };
|
|
16
|
+
});
|
|
17
|
+
fastify.get("/admin/seats", async (request, reply) => {
|
|
18
|
+
const db = getDb();
|
|
19
|
+
const seats = db.prepare("SELECT * FROM seats ORDER BY created_at DESC").all();
|
|
20
|
+
return { seats, count: seats.length };
|
|
21
|
+
});
|
|
22
|
+
fastify.patch("/admin/seats/:id", async (request, reply) => {
|
|
23
|
+
const { id } = request.params;
|
|
24
|
+
const { status } = request.body || {};
|
|
25
|
+
if (!status || !["active", "suspended", "cancelled"].includes(status)) {
|
|
26
|
+
return reply.code(400).send({ error: "valid status is required (active, suspended, cancelled)" });
|
|
27
|
+
}
|
|
28
|
+
const db = getDb();
|
|
29
|
+
const result = db.prepare("UPDATE seats SET status = ?, updated_at = datetime('now') WHERE id = ?").run(status, id);
|
|
30
|
+
if (result.changes === 0) {
|
|
31
|
+
return reply.code(404).send({ error: "seat not found" });
|
|
32
|
+
}
|
|
33
|
+
if (status !== "active") {
|
|
34
|
+
db.prepare("UPDATE api_tokens SET status = 'revoked', revoked_at = datetime('now') WHERE seat_id = ? AND status = 'active'").run(id);
|
|
35
|
+
}
|
|
36
|
+
const seat = db.prepare("SELECT * FROM seats WHERE id = ?").get(id);
|
|
37
|
+
return { ok: true, seat };
|
|
38
|
+
});
|
|
39
|
+
fastify.post("/admin/tokens", async (request, reply) => {
|
|
40
|
+
const { seat_id, label, expires_at } = request.body || {};
|
|
41
|
+
if (!seat_id) {
|
|
42
|
+
return reply.code(400).send({ error: "seat_id is required" });
|
|
43
|
+
}
|
|
44
|
+
const db = getDb();
|
|
45
|
+
const seat = db.prepare("SELECT * FROM seats WHERE id = ?").get(seat_id);
|
|
46
|
+
if (!seat) {
|
|
47
|
+
return reply.code(404).send({ error: "seat not found" });
|
|
48
|
+
}
|
|
49
|
+
const token = generateToken();
|
|
50
|
+
const result = db.prepare("INSERT INTO api_tokens (token, seat_id, label, expires_at) VALUES (?, ?, ?, ?)").run(token, seat_id, label || null, expires_at || null);
|
|
51
|
+
const tokenRow = db.prepare("SELECT * FROM api_tokens WHERE id = ?").get(result.lastInsertRowid);
|
|
52
|
+
return { ok: true, token: tokenRow };
|
|
53
|
+
});
|
|
54
|
+
fastify.get("/admin/tokens", async (request, reply) => {
|
|
55
|
+
const db = getDb();
|
|
56
|
+
const tokens = db.prepare(`
|
|
57
|
+
SELECT t.*, s.name as seat_name, s.email as seat_email, s.status as seat_status
|
|
58
|
+
FROM api_tokens t
|
|
59
|
+
JOIN seats s ON t.seat_id = s.id
|
|
60
|
+
ORDER BY t.created_at DESC
|
|
61
|
+
`).all();
|
|
62
|
+
return { tokens, count: tokens.length };
|
|
63
|
+
});
|
|
64
|
+
fastify.patch("/admin/tokens/:id", async (request, reply) => {
|
|
65
|
+
const { id } = request.params;
|
|
66
|
+
const { status } = request.body || {};
|
|
67
|
+
if (!status || !["active", "revoked", "expired"].includes(status)) {
|
|
68
|
+
return reply.code(400).send({ error: "valid status is required (active, revoked, expired)" });
|
|
69
|
+
}
|
|
70
|
+
const db = getDb();
|
|
71
|
+
const update = status === "revoked"
|
|
72
|
+
? "UPDATE api_tokens SET status = ?, revoked_at = datetime('now') WHERE id = ?"
|
|
73
|
+
: "UPDATE api_tokens SET status = ? WHERE id = ?";
|
|
74
|
+
const result = db.prepare(update).run(status, id);
|
|
75
|
+
if (result.changes === 0) {
|
|
76
|
+
return reply.code(404).send({ error: "token not found" });
|
|
77
|
+
}
|
|
78
|
+
const token = db.prepare("SELECT * FROM api_tokens WHERE id = ?").get(id);
|
|
79
|
+
return { ok: true, token };
|
|
80
|
+
});
|
|
81
|
+
fastify.get("/admin/usage", async (request, reply) => {
|
|
82
|
+
const { days: daysRaw } = request.query || {};
|
|
83
|
+
const days = Number(daysRaw);
|
|
84
|
+
if (daysRaw !== undefined && (isNaN(days) || !Number.isFinite(days) || !Number.isInteger(days) || days < 1 || days > 365)) {
|
|
85
|
+
return reply.code(400).send({ error: "days must be a positive integer between 1 and 365" });
|
|
86
|
+
}
|
|
87
|
+
const effectiveDays = days || 30;
|
|
88
|
+
const db = getDb();
|
|
89
|
+
const sql = "SELECT t.token, t.label, s.name as seat_name, COUNT(*) as request_count, AVG(l.latency_ms) as avg_latency_ms, MIN(l.created_at) as first_used, MAX(l.created_at) as last_used FROM usage_log l JOIN api_tokens t ON l.token_id = t.id JOIN seats s ON t.seat_id = s.id WHERE l.created_at >= datetime('now', ?) GROUP BY t.id ORDER BY request_count DESC";
|
|
90
|
+
const usage = db.prepare(sql).all("-" + effectiveDays + " days");
|
|
91
|
+
return { usage, count: usage.length, days: effectiveDays };
|
|
92
|
+
});
|
|
93
|
+
}
|
package/routes/admin.ts
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { getDb } from "../lib/db.js"
|
|
2
|
+
import { randomBytes } from "node:crypto"
|
|
3
|
+
|
|
4
|
+
function generateToken() {
|
|
5
|
+
return "vos_" + randomBytes(32).toString("hex")
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export async function adminRoutes(fastify: any) {
|
|
9
|
+
fastify.post("/admin/seats", async (request: any, reply: any) => {
|
|
10
|
+
const { name, email } = request.body || {}
|
|
11
|
+
if (!name) {
|
|
12
|
+
return reply.code(400).send({ error: "name is required" })
|
|
13
|
+
}
|
|
14
|
+
const db = getDb()
|
|
15
|
+
const result = db.prepare("INSERT INTO seats (name, email) VALUES (?, ?)").run(name, email || null)
|
|
16
|
+
const seat = db.prepare("SELECT * FROM seats WHERE id = ?").get(result.lastInsertRowid)
|
|
17
|
+
return { ok: true, seat }
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
fastify.get("/admin/seats", async (request: any, reply: any) => {
|
|
21
|
+
const db = getDb()
|
|
22
|
+
const seats = db.prepare("SELECT * FROM seats ORDER BY created_at DESC").all()
|
|
23
|
+
return { seats, count: seats.length }
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
fastify.patch("/admin/seats/:id", async (request: any, reply: any) => {
|
|
27
|
+
const { id } = request.params
|
|
28
|
+
const { status } = request.body || {}
|
|
29
|
+
if (!status || !["active", "suspended", "cancelled"].includes(status)) {
|
|
30
|
+
return reply.code(400).send({ error: "valid status is required (active, suspended, cancelled)" })
|
|
31
|
+
}
|
|
32
|
+
const db = getDb()
|
|
33
|
+
const result = db.prepare("UPDATE seats SET status = ?, updated_at = datetime('now') WHERE id = ?").run(status, id)
|
|
34
|
+
if (result.changes === 0) {
|
|
35
|
+
return reply.code(404).send({ error: "seat not found" })
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (status !== "active") {
|
|
39
|
+
db.prepare("UPDATE api_tokens SET status = 'revoked', revoked_at = datetime('now') WHERE seat_id = ? AND status = 'active'").run(id)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const seat = db.prepare("SELECT * FROM seats WHERE id = ?").get(id)
|
|
43
|
+
return { ok: true, seat }
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
fastify.post("/admin/tokens", async (request: any, reply: any) => {
|
|
47
|
+
const { seat_id, label, expires_at } = request.body || {}
|
|
48
|
+
if (!seat_id) {
|
|
49
|
+
return reply.code(400).send({ error: "seat_id is required" })
|
|
50
|
+
}
|
|
51
|
+
const db = getDb()
|
|
52
|
+
const seat = db.prepare("SELECT * FROM seats WHERE id = ?").get(seat_id)
|
|
53
|
+
if (!seat) {
|
|
54
|
+
return reply.code(404).send({ error: "seat not found" })
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const token = generateToken()
|
|
58
|
+
const result = db.prepare(
|
|
59
|
+
"INSERT INTO api_tokens (token, seat_id, label, expires_at) VALUES (?, ?, ?, ?)"
|
|
60
|
+
).run(token, seat_id, label || null, expires_at || null)
|
|
61
|
+
|
|
62
|
+
const tokenRow = db.prepare("SELECT * FROM api_tokens WHERE id = ?").get(result.lastInsertRowid)
|
|
63
|
+
return { ok: true, token: tokenRow }
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
fastify.get("/admin/tokens", async (request: any, reply: any) => {
|
|
67
|
+
const db = getDb()
|
|
68
|
+
const tokens = db.prepare(`
|
|
69
|
+
SELECT t.*, s.name as seat_name, s.email as seat_email, s.status as seat_status
|
|
70
|
+
FROM api_tokens t
|
|
71
|
+
JOIN seats s ON t.seat_id = s.id
|
|
72
|
+
ORDER BY t.created_at DESC
|
|
73
|
+
`).all()
|
|
74
|
+
return { tokens, count: tokens.length }
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
fastify.patch("/admin/tokens/:id", async (request: any, reply: any) => {
|
|
78
|
+
const { id } = request.params
|
|
79
|
+
const { status } = request.body || {}
|
|
80
|
+
if (!status || !["active", "revoked", "expired"].includes(status)) {
|
|
81
|
+
return reply.code(400).send({ error: "valid status is required (active, revoked, expired)" })
|
|
82
|
+
}
|
|
83
|
+
const db = getDb()
|
|
84
|
+
const update = status === "revoked"
|
|
85
|
+
? "UPDATE api_tokens SET status = ?, revoked_at = datetime('now') WHERE id = ?"
|
|
86
|
+
: "UPDATE api_tokens SET status = ? WHERE id = ?"
|
|
87
|
+
const result = db.prepare(update).run(status, id)
|
|
88
|
+
if (result.changes === 0) {
|
|
89
|
+
return reply.code(404).send({ error: "token not found" })
|
|
90
|
+
}
|
|
91
|
+
const token = db.prepare("SELECT * FROM api_tokens WHERE id = ?").get(id)
|
|
92
|
+
return { ok: true, token }
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
fastify.get("/admin/usage", async (request: any, reply: any) => {
|
|
96
|
+
const { days: daysRaw } = request.query || {}
|
|
97
|
+
const days = Number(daysRaw)
|
|
98
|
+
if (daysRaw !== undefined && (isNaN(days) || !Number.isFinite(days) || !Number.isInteger(days) || days < 1 || days > 365)) {
|
|
99
|
+
return reply.code(400).send({ error: "days must be a positive integer between 1 and 365" })
|
|
100
|
+
}
|
|
101
|
+
const effectiveDays = days || 30
|
|
102
|
+
const db = getDb()
|
|
103
|
+
const sql = "SELECT t.token, t.label, s.name as seat_name, COUNT(*) as request_count, AVG(l.latency_ms) as avg_latency_ms, MIN(l.created_at) as first_used, MAX(l.created_at) as last_used FROM usage_log l JOIN api_tokens t ON l.token_id = t.id JOIN seats s ON t.seat_id = s.id WHERE l.created_at >= datetime('now', ?) GROUP BY t.id ORDER BY request_count DESC"
|
|
104
|
+
const usage = db.prepare(sql).all("-" + effectiveDays + " days")
|
|
105
|
+
return { usage, count: usage.length, days: effectiveDays }
|
|
106
|
+
})
|
|
107
|
+
}
|