ahok-skill 1.3.1
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/.prettierrc +8 -0
- package/Dockerfile +59 -0
- package/RAW_SKILL.md +219 -0
- package/README.md +277 -0
- package/SKILL.md +58 -0
- package/bin/opm.js +268 -0
- package/data/openmemory.sqlite +0 -0
- package/data/openmemory.sqlite-shm +0 -0
- package/data/openmemory.sqlite-wal +0 -0
- package/dist/ai/graph.js +293 -0
- package/dist/ai/mcp.js +397 -0
- package/dist/cli.js +78 -0
- package/dist/core/cfg.js +87 -0
- package/dist/core/db.js +636 -0
- package/dist/core/memory.js +116 -0
- package/dist/core/migrate.js +227 -0
- package/dist/core/models.js +105 -0
- package/dist/core/telemetry.js +57 -0
- package/dist/core/types.js +2 -0
- package/dist/core/vector/postgres.js +52 -0
- package/dist/core/vector/valkey.js +246 -0
- package/dist/core/vector_store.js +2 -0
- package/dist/index.js +44 -0
- package/dist/memory/decay.js +301 -0
- package/dist/memory/embed.js +675 -0
- package/dist/memory/hsg.js +959 -0
- package/dist/memory/reflect.js +131 -0
- package/dist/memory/user_summary.js +99 -0
- package/dist/migrate.js +9 -0
- package/dist/ops/compress.js +255 -0
- package/dist/ops/dynamics.js +189 -0
- package/dist/ops/extract.js +333 -0
- package/dist/ops/ingest.js +214 -0
- package/dist/server/index.js +109 -0
- package/dist/server/middleware/auth.js +137 -0
- package/dist/server/routes/auth.js +186 -0
- package/dist/server/routes/compression.js +108 -0
- package/dist/server/routes/dashboard.js +399 -0
- package/dist/server/routes/docs.js +241 -0
- package/dist/server/routes/dynamics.js +312 -0
- package/dist/server/routes/ide.js +280 -0
- package/dist/server/routes/index.js +33 -0
- package/dist/server/routes/keys.js +132 -0
- package/dist/server/routes/langgraph.js +61 -0
- package/dist/server/routes/memory.js +213 -0
- package/dist/server/routes/sources.js +140 -0
- package/dist/server/routes/system.js +63 -0
- package/dist/server/routes/temporal.js +293 -0
- package/dist/server/routes/users.js +101 -0
- package/dist/server/routes/vercel.js +57 -0
- package/dist/server/server.js +211 -0
- package/dist/server.js +3 -0
- package/dist/sources/base.js +223 -0
- package/dist/sources/github.js +171 -0
- package/dist/sources/google_drive.js +166 -0
- package/dist/sources/google_sheets.js +112 -0
- package/dist/sources/google_slides.js +139 -0
- package/dist/sources/index.js +34 -0
- package/dist/sources/notion.js +165 -0
- package/dist/sources/onedrive.js +143 -0
- package/dist/sources/web_crawler.js +166 -0
- package/dist/temporal_graph/index.js +20 -0
- package/dist/temporal_graph/query.js +240 -0
- package/dist/temporal_graph/store.js +116 -0
- package/dist/temporal_graph/timeline.js +241 -0
- package/dist/temporal_graph/types.js +2 -0
- package/dist/utils/chunking.js +60 -0
- package/dist/utils/index.js +31 -0
- package/dist/utils/keyword.js +94 -0
- package/dist/utils/text.js +120 -0
- package/nodemon.json +7 -0
- package/package.json +50 -0
- package/references/api_reference.md +66 -0
- package/references/examples.md +45 -0
- package/src/ai/graph.ts +363 -0
- package/src/ai/mcp.ts +494 -0
- package/src/cli.ts +94 -0
- package/src/core/cfg.ts +110 -0
- package/src/core/db.ts +1052 -0
- package/src/core/memory.ts +99 -0
- package/src/core/migrate.ts +302 -0
- package/src/core/models.ts +107 -0
- package/src/core/telemetry.ts +47 -0
- package/src/core/types.ts +130 -0
- package/src/core/vector/postgres.ts +61 -0
- package/src/core/vector/valkey.ts +261 -0
- package/src/core/vector_store.ts +9 -0
- package/src/index.ts +5 -0
- package/src/memory/decay.ts +427 -0
- package/src/memory/embed.ts +707 -0
- package/src/memory/hsg.ts +1245 -0
- package/src/memory/reflect.ts +158 -0
- package/src/memory/user_summary.ts +110 -0
- package/src/migrate.ts +8 -0
- package/src/ops/compress.ts +296 -0
- package/src/ops/dynamics.ts +272 -0
- package/src/ops/extract.ts +360 -0
- package/src/ops/ingest.ts +286 -0
- package/src/server/index.ts +159 -0
- package/src/server/middleware/auth.ts +156 -0
- package/src/server/routes/auth.ts +223 -0
- package/src/server/routes/compression.ts +106 -0
- package/src/server/routes/dashboard.ts +420 -0
- package/src/server/routes/docs.ts +380 -0
- package/src/server/routes/dynamics.ts +516 -0
- package/src/server/routes/ide.ts +283 -0
- package/src/server/routes/index.ts +32 -0
- package/src/server/routes/keys.ts +131 -0
- package/src/server/routes/langgraph.ts +71 -0
- package/src/server/routes/memory.ts +440 -0
- package/src/server/routes/sources.ts +111 -0
- package/src/server/routes/system.ts +68 -0
- package/src/server/routes/temporal.ts +335 -0
- package/src/server/routes/users.ts +111 -0
- package/src/server/routes/vercel.ts +55 -0
- package/src/server/server.js +215 -0
- package/src/server.ts +1 -0
- package/src/sources/base.ts +257 -0
- package/src/sources/github.ts +156 -0
- package/src/sources/google_drive.ts +144 -0
- package/src/sources/google_sheets.ts +85 -0
- package/src/sources/google_slides.ts +115 -0
- package/src/sources/index.ts +19 -0
- package/src/sources/notion.ts +148 -0
- package/src/sources/onedrive.ts +131 -0
- package/src/sources/web_crawler.ts +161 -0
- package/src/temporal_graph/index.ts +4 -0
- package/src/temporal_graph/query.ts +299 -0
- package/src/temporal_graph/store.ts +156 -0
- package/src/temporal_graph/timeline.ts +319 -0
- package/src/temporal_graph/types.ts +41 -0
- package/src/utils/chunking.ts +66 -0
- package/src/utils/index.ts +25 -0
- package/src/utils/keyword.ts +137 -0
- package/src/utils/text.ts +115 -0
- package/tests/test_api_workspace_management.ts +413 -0
- package/tests/test_bulk_delete.ts +267 -0
- package/tests/test_omnibus.ts +166 -0
- package/tests/test_workspace_management.ts +278 -0
- package/tests/verify.ts +104 -0
- package/tsconfig.json +15 -0
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
import { q } from "../../core/db";
|
|
2
|
+
import { env } from "../../core/cfg";
|
|
3
|
+
import crypto from "crypto";
|
|
4
|
+
import Stripe from "stripe";
|
|
5
|
+
|
|
6
|
+
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY || "", {
|
|
7
|
+
apiVersion: "2025-01-27.acacia" as any,
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
import { createClerkClient, verifyToken } from "@clerk/backend";
|
|
11
|
+
|
|
12
|
+
const clerk = createClerkClient({ secretKey: process.env.CLERK_SECRET_KEY });
|
|
13
|
+
|
|
14
|
+
export const auth = (app: any) => {
|
|
15
|
+
// Sync user from Clerk with JWT verification
|
|
16
|
+
app.post("/auth/clerk-sync", async (req: any, res: any) => {
|
|
17
|
+
try {
|
|
18
|
+
const token = req.headers.authorization?.replace("Bearer ", "");
|
|
19
|
+
if (!token) return res.status(401).json({ error: "No token provided" });
|
|
20
|
+
|
|
21
|
+
const session = await verifyToken(token, { secretKey: process.env.CLERK_SECRET_KEY });
|
|
22
|
+
const clerk_id = session.sub;
|
|
23
|
+
const { email } = req.body;
|
|
24
|
+
|
|
25
|
+
let user = await q.get_user_by_clerk_id.get(clerk_id);
|
|
26
|
+
if (!user) {
|
|
27
|
+
// Create new user
|
|
28
|
+
const user_id = crypto.randomUUID();
|
|
29
|
+
const api_key = `opm_${crypto.randomBytes(24).toString("hex")}`;
|
|
30
|
+
|
|
31
|
+
// Create Stripe customer
|
|
32
|
+
let stripe_customer_id = "";
|
|
33
|
+
try {
|
|
34
|
+
const customer = await stripe.customers.create({
|
|
35
|
+
email,
|
|
36
|
+
metadata: { clerk_id, user_id },
|
|
37
|
+
});
|
|
38
|
+
stripe_customer_id = customer.id;
|
|
39
|
+
} catch (e) {
|
|
40
|
+
console.error("[STRIPE] Customer creation failed:", e);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
await q.ins_user.run(
|
|
44
|
+
user_id,
|
|
45
|
+
clerk_id,
|
|
46
|
+
api_key,
|
|
47
|
+
stripe_customer_id,
|
|
48
|
+
null, // subscription_id
|
|
49
|
+
100, // free tier capacity (100 memories)
|
|
50
|
+
0, // current usage
|
|
51
|
+
"", // summary
|
|
52
|
+
0, // reflection_count
|
|
53
|
+
Date.now(),
|
|
54
|
+
Date.now()
|
|
55
|
+
);
|
|
56
|
+
user = await q.get_user_by_clerk_id.get(clerk_id);
|
|
57
|
+
} else if (!user.stripe_customer_id && email) {
|
|
58
|
+
// Backward compatibility: create Stripe customer for existing user
|
|
59
|
+
try {
|
|
60
|
+
const customer = await stripe.customers.create({
|
|
61
|
+
email,
|
|
62
|
+
metadata: { clerk_id: user.clerk_id, user_id: user.user_id },
|
|
63
|
+
});
|
|
64
|
+
await q.upd_user_billing.run(
|
|
65
|
+
user.user_id,
|
|
66
|
+
customer.id,
|
|
67
|
+
user.stripe_subscription_id,
|
|
68
|
+
user.memory_capacity,
|
|
69
|
+
Date.now()
|
|
70
|
+
);
|
|
71
|
+
user.stripe_customer_id = customer.id;
|
|
72
|
+
console.log(`[STRIPE] Fixed missing customer for ${clerk_id}`);
|
|
73
|
+
} catch (e) {
|
|
74
|
+
console.error("[STRIPE] Customer repair failed:", e);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
res.json(user);
|
|
79
|
+
} catch (err: any) {
|
|
80
|
+
console.error("[AUTH] Clerk Sync Error:", err);
|
|
81
|
+
res.status(500).json({ error: err.message, stack: err.stack });
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
// Create Stripe Checkout Session with JWT verification
|
|
86
|
+
app.post("/auth/create-checkout", async (req: any, res: any) => {
|
|
87
|
+
try {
|
|
88
|
+
const token = req.headers.authorization?.replace("Bearer ", "");
|
|
89
|
+
if (!token) return res.status(401).json({ error: "No token provided" });
|
|
90
|
+
|
|
91
|
+
const clerkSession = await verifyToken(token, { secretKey: process.env.CLERK_SECRET_KEY });
|
|
92
|
+
const clerk_id = clerkSession.sub;
|
|
93
|
+
const { plan } = req.body;
|
|
94
|
+
|
|
95
|
+
const user = await q.get_user_by_clerk_id.get(clerk_id);
|
|
96
|
+
if (!user) return res.status(404).json({ error: "User not found" });
|
|
97
|
+
|
|
98
|
+
const priceMap: Record<string, number> = {
|
|
99
|
+
"starter": 2000, // $20.00/month
|
|
100
|
+
"pro": 10000, // $100.00/month
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
const checkoutOptions: Stripe.Checkout.SessionCreateParams = {
|
|
104
|
+
payment_method_types: ["card"],
|
|
105
|
+
line_items: [{
|
|
106
|
+
price_data: {
|
|
107
|
+
currency: "usd",
|
|
108
|
+
product_data: {
|
|
109
|
+
name: `OpenMemory ${plan.toUpperCase()} Plan`,
|
|
110
|
+
},
|
|
111
|
+
unit_amount: priceMap[plan] || 2000,
|
|
112
|
+
recurring: { interval: "month" },
|
|
113
|
+
},
|
|
114
|
+
quantity: 1,
|
|
115
|
+
}],
|
|
116
|
+
mode: "subscription",
|
|
117
|
+
success_url: `${process.env.DASHBOARD_URL}/success?session_id={CHECKOUT_SESSION_ID}`,
|
|
118
|
+
cancel_url: `${process.env.DASHBOARD_URL}/cancel`,
|
|
119
|
+
metadata: { clerk_id, plan },
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
if (user.stripe_customer_id) {
|
|
123
|
+
checkoutOptions.customer = user.stripe_customer_id;
|
|
124
|
+
} else {
|
|
125
|
+
// Should have been fixed by clerk-sync, but use email as fallback
|
|
126
|
+
const clerkUser = await clerk.users.getUser(clerk_id);
|
|
127
|
+
checkoutOptions.customer_email = clerkUser.emailAddresses[0]?.emailAddress;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const session = await stripe.checkout.sessions.create(checkoutOptions);
|
|
131
|
+
|
|
132
|
+
res.json({ url: session.url });
|
|
133
|
+
} catch (err: any) {
|
|
134
|
+
console.error("[STRIPE] Checkout Error:", err);
|
|
135
|
+
res.status(500).json({ error: err.message, stack: err.stack });
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
// Create Stripe Customer Portal Session
|
|
140
|
+
app.post("/auth/create-portal", async (req: any, res: any) => {
|
|
141
|
+
try {
|
|
142
|
+
const token = req.headers.authorization?.replace("Bearer ", "");
|
|
143
|
+
if (!token) return res.status(401).json({ error: "No token provided" });
|
|
144
|
+
|
|
145
|
+
const clerkSession = await verifyToken(token, { secretKey: process.env.CLERK_SECRET_KEY });
|
|
146
|
+
const clerk_id = clerkSession.sub;
|
|
147
|
+
|
|
148
|
+
const user = await q.get_user_by_clerk_id.get(clerk_id);
|
|
149
|
+
if (!user || !user.stripe_customer_id) {
|
|
150
|
+
return res.status(400).json({ error: "User or customer not found" });
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const session = await stripe.billingPortal.sessions.create({
|
|
154
|
+
customer: user.stripe_customer_id,
|
|
155
|
+
return_url: `${process.env.DASHBOARD_URL}/dashboard`,
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
res.json({ url: session.url });
|
|
159
|
+
} catch (err: any) {
|
|
160
|
+
console.error("[STRIPE] Portal Error:", err);
|
|
161
|
+
res.status(500).json({ error: err.message });
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
// Stripe Webhook
|
|
166
|
+
app.post("/auth/stripe-webhook", async (req: any, res: any) => {
|
|
167
|
+
const sig = req.headers["stripe-signature"];
|
|
168
|
+
let event;
|
|
169
|
+
|
|
170
|
+
try {
|
|
171
|
+
event = stripe.webhooks.constructEvent(
|
|
172
|
+
req.rawBody || JSON.stringify(req.body),
|
|
173
|
+
sig,
|
|
174
|
+
process.env.STRIPE_WEBHOOK_SECRET || ""
|
|
175
|
+
);
|
|
176
|
+
} catch (err: any) {
|
|
177
|
+
return res.status(400).send(`Webhook Error: ${err.message}`);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
if (event.type === "checkout.session.completed") {
|
|
181
|
+
const session = event.data.object as Stripe.Checkout.Session;
|
|
182
|
+
const clerk_id = session.metadata?.clerk_id;
|
|
183
|
+
const plan = session.metadata?.plan;
|
|
184
|
+
|
|
185
|
+
if (clerk_id) {
|
|
186
|
+
const user = await q.get_user_by_clerk_id.get(clerk_id);
|
|
187
|
+
if (user) {
|
|
188
|
+
const capacityMap: Record<string, number> = {
|
|
189
|
+
"starter": 10000, // 10,000 memories
|
|
190
|
+
"pro": 100000, // 100,000 memories
|
|
191
|
+
};
|
|
192
|
+
const new_capacity = capacityMap[plan!] || 10000;
|
|
193
|
+
await q.upd_user_billing.run(
|
|
194
|
+
user.user_id,
|
|
195
|
+
user.stripe_customer_id,
|
|
196
|
+
session.subscription as string,
|
|
197
|
+
new_capacity,
|
|
198
|
+
Date.now()
|
|
199
|
+
);
|
|
200
|
+
console.log(`[STRIPE] Updated capacity for ${clerk_id} to ${new_capacity}`);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
} else if (event.type === "customer.subscription.deleted") {
|
|
204
|
+
const subscription = event.data.object as Stripe.Subscription;
|
|
205
|
+
const customer_id = subscription.customer as string;
|
|
206
|
+
|
|
207
|
+
// Downgrade user to free tier
|
|
208
|
+
const user = await q.get_user_by_stripe_customer_id.get(customer_id);
|
|
209
|
+
if (user) {
|
|
210
|
+
await q.upd_user_billing.run(
|
|
211
|
+
user.user_id,
|
|
212
|
+
user.stripe_customer_id,
|
|
213
|
+
null,
|
|
214
|
+
100, // back to free tier (100 memories)
|
|
215
|
+
Date.now()
|
|
216
|
+
);
|
|
217
|
+
console.log(`[STRIPE] Downgraded ${user.clerk_id} to free tier`);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
res.json({ received: true });
|
|
222
|
+
});
|
|
223
|
+
};
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { compressionEngine, CompressionMetrics } from "../../ops/compress";
|
|
2
|
+
|
|
3
|
+
export function compression(app: any) {
|
|
4
|
+
app.post("/api/compression/compress", async (req: any, res: any) => {
|
|
5
|
+
try {
|
|
6
|
+
const { text, algorithm } = req.body;
|
|
7
|
+
if (!text) return res.status(400).json({ error: "text required" });
|
|
8
|
+
let r;
|
|
9
|
+
if (
|
|
10
|
+
algorithm &&
|
|
11
|
+
["semantic", "syntactic", "aggressive"].includes(algorithm)
|
|
12
|
+
) {
|
|
13
|
+
r = compressionEngine.compress(text, algorithm);
|
|
14
|
+
} else {
|
|
15
|
+
r = compressionEngine.auto(text);
|
|
16
|
+
}
|
|
17
|
+
res.json({ ok: true, comp: r.comp, m: r.metrics, hash: r.hash });
|
|
18
|
+
} catch (e: any) {
|
|
19
|
+
res.status(500).json({ error: e.message });
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
app.post("/api/compression/batch", async (req: any, res: any) => {
|
|
24
|
+
try {
|
|
25
|
+
const { texts, algorithm = "semantic" } = req.body;
|
|
26
|
+
if (!Array.isArray(texts))
|
|
27
|
+
return res.status(400).json({ error: "texts must be array" });
|
|
28
|
+
if (!["semantic", "syntactic", "aggressive"].includes(algorithm))
|
|
29
|
+
return res.status(400).json({ error: "invalid algo" });
|
|
30
|
+
const r = compressionEngine.batch(texts, algorithm);
|
|
31
|
+
res.json({
|
|
32
|
+
ok: true,
|
|
33
|
+
results: r.map((x: any) => ({
|
|
34
|
+
comp: x.comp,
|
|
35
|
+
m: x.metrics,
|
|
36
|
+
hash: x.hash,
|
|
37
|
+
})),
|
|
38
|
+
total: r.reduce((s: any, x: any) => s + x.metrics.saved, 0),
|
|
39
|
+
});
|
|
40
|
+
} catch (e: any) {
|
|
41
|
+
res.status(500).json({ error: e.message });
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
app.post("/api/compression/analyze", async (req: any, res: any) => {
|
|
46
|
+
try {
|
|
47
|
+
const { text } = req.body;
|
|
48
|
+
if (!text) return res.status(400).json({ error: "text required" });
|
|
49
|
+
const a = compressionEngine.analyze(text);
|
|
50
|
+
let best = "semantic";
|
|
51
|
+
let max = 0;
|
|
52
|
+
for (const [algo, m] of Object.entries(a)) {
|
|
53
|
+
const met = m as CompressionMetrics;
|
|
54
|
+
if (met.pct > max) {
|
|
55
|
+
max = met.pct;
|
|
56
|
+
best = algo;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
res.json({
|
|
60
|
+
ok: true,
|
|
61
|
+
analysis: a,
|
|
62
|
+
rec: {
|
|
63
|
+
algo: best,
|
|
64
|
+
save: (a as any)[best].pct.toFixed(2) + "%",
|
|
65
|
+
lat: (a as any)[best].latency.toFixed(2) + "ms",
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
} catch (e: any) {
|
|
69
|
+
res.status(500).json({ error: e.message });
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
app.get("/api/compression/stats", async (req: any, res: any) => {
|
|
74
|
+
try {
|
|
75
|
+
const s = compressionEngine.getStats();
|
|
76
|
+
res.json({
|
|
77
|
+
ok: true,
|
|
78
|
+
stats: {
|
|
79
|
+
...s,
|
|
80
|
+
avgRatio: (s.avgRatio * 100).toFixed(2) + "%",
|
|
81
|
+
totalPct:
|
|
82
|
+
s.ogTok > 0
|
|
83
|
+
? ((s.saved / s.ogTok) * 100).toFixed(2) + "%"
|
|
84
|
+
: "0%",
|
|
85
|
+
lat: s.latency.toFixed(2) + "ms",
|
|
86
|
+
avgLat:
|
|
87
|
+
s.total > 0
|
|
88
|
+
? (s.latency / s.total).toFixed(2) + "ms"
|
|
89
|
+
: "0ms",
|
|
90
|
+
},
|
|
91
|
+
});
|
|
92
|
+
} catch (e: any) {
|
|
93
|
+
res.status(500).json({ error: e.message });
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
app.post("/api/compression/reset", async (req: any, res: any) => {
|
|
98
|
+
try {
|
|
99
|
+
compressionEngine.reset();
|
|
100
|
+
compressionEngine.clear();
|
|
101
|
+
res.json({ ok: true, msg: "reset done" });
|
|
102
|
+
} catch (e: any) {
|
|
103
|
+
res.status(500).json({ error: e.message });
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
}
|