maverick-ai-cli 1.0.0

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.
@@ -0,0 +1,104 @@
1
+ import fs from "node:fs/promises";
2
+ import chalk from "chalk";
3
+ import path from "path";
4
+ import os from "os";
5
+
6
+ // Token file paths
7
+ export const CONFIG_DIR = path.join(os.homedir(), ".better-auth");
8
+ export const TOKEN_FILE = path.join(CONFIG_DIR, "token.json");
9
+
10
+ /**
11
+ * Read the stored token data safely
12
+ */
13
+ export async function getStoredToken() {
14
+ try {
15
+ const data = await fs.readFile(TOKEN_FILE, "utf-8");
16
+ return JSON.parse(data);
17
+ } catch {
18
+ return null;
19
+ }
20
+ }
21
+
22
+ /**
23
+ * Store a token with metadata
24
+ */
25
+ export async function storeToken(token) {
26
+ try {
27
+ await fs.mkdir(CONFIG_DIR, { recursive: true });
28
+
29
+ const tokenData = {
30
+ access_token: token.access_token,
31
+ refresh_token: token.refresh_token,
32
+ token_type: token.token_type || "Bearer",
33
+ scope: token.scope,
34
+ expires_at: token.expires_in
35
+ ? new Date(Date.now() + token.expires_in * 1000).toISOString()
36
+ : null,
37
+ created_at: new Date().toISOString(),
38
+ };
39
+
40
+ await fs.writeFile(
41
+ TOKEN_FILE,
42
+ JSON.stringify(tokenData, null, 2),
43
+ "utf-8"
44
+ );
45
+
46
+ return true;
47
+ } catch (err) {
48
+ console.error(chalk.red("Failed to store token:"), err.message);
49
+ return false;
50
+ }
51
+ }
52
+
53
+ /**
54
+ * Remove stored token
55
+ */
56
+ export async function clearStoredToken() {
57
+ try {
58
+ await fs.rm(TOKEN_FILE, { force: true });
59
+ console.log(chalk.yellow("⚠ Token cleared"));
60
+ return true;
61
+ } catch (err) {
62
+ console.error(chalk.red("Failed to clear token:"), err.message);
63
+ return false;
64
+ }
65
+ }
66
+
67
+ /**
68
+ * Check if token is expired or about to expire (5 min window)
69
+ */
70
+ export async function isTokenExpired() {
71
+ const token = await getStoredToken();
72
+
73
+ if (!token || !token.expires_at) {
74
+ return true;
75
+ }
76
+
77
+ const expiresAt = new Date(token.expires_at).getTime();
78
+ const now = Date.now();
79
+
80
+ // token is considered expired if less than 5 minutes remain
81
+ const FIVE_MINUTES = 5 * 60 * 1000;
82
+ return expiresAt - now < FIVE_MINUTES;
83
+ }
84
+
85
+ /**
86
+ * Require a valid token for authenticated commands
87
+ */
88
+ export async function requireAuth() {
89
+ const token = await getStoredToken();
90
+
91
+ if (!token) {
92
+ console.log(chalk.red("You are not logged in."));
93
+ console.log(chalk.gray("Run: your-cli login\n"));
94
+ process.exit(1);
95
+ }
96
+
97
+ if (await isTokenExpired()) {
98
+ console.log(chalk.yellow("Your session has expired."));
99
+ console.log(chalk.gray("Run: your-cli login\n"));
100
+ process.exit(1);
101
+ }
102
+
103
+ return token;
104
+ }
@@ -0,0 +1,117 @@
1
+
2
+ import prisma from "../lib/db.js"
3
+
4
+ export class ChatService {
5
+
6
+ async createConversation(userId, mode = "chat", title = null) {
7
+ return prisma.conversation.create({
8
+ data: {
9
+ userId,
10
+ mode,
11
+ title: title || `New ${mode} conversation`
12
+ }
13
+ })
14
+ }
15
+
16
+ async getOrCreateConversation(userId, conversationId = null, mode = "chat") {
17
+ if (conversationId) {
18
+ const conversation = await prisma.conversation.findFirst({
19
+ where: {
20
+ id: conversationId,
21
+ userId
22
+ },
23
+ include: {
24
+ messages: {
25
+ orderBy: {
26
+ createdAt: "asc"
27
+ }
28
+ }
29
+ }
30
+ });
31
+
32
+ if (conversation) {
33
+ return conversation
34
+ }
35
+ }
36
+
37
+ return await this.createConversation(userId, mode)
38
+ }
39
+
40
+ async createMessage(conversationId, role, content) {
41
+ const contentStr = typeof content === "string"
42
+ ? content
43
+ : JSON.stringify(content);
44
+
45
+ return await prisma.message.create({
46
+ data: {
47
+ conversationId,
48
+ role,
49
+ content: contentStr
50
+ }
51
+ })
52
+ }
53
+
54
+
55
+ async getMessages(conversationId) {
56
+ const messages = await prisma.message.findMany({
57
+ where: { conversationId },
58
+ orderBy: { createdAt: "asc" }
59
+ })
60
+
61
+ return messages.map((msg) => ({
62
+ ...msg,
63
+ content: this.parseContent(msg.content)
64
+ }))
65
+ }
66
+
67
+
68
+
69
+ async getUserConversation(userId) {
70
+ return await prisma.conversation.findMany({
71
+ where: { userId },
72
+ orderBy: { updatedAt: "desc" },
73
+ include: {
74
+ messages: {
75
+ take: 1,
76
+ orderBy: { createdAt: "desc" }
77
+ }
78
+ }
79
+ })
80
+ }
81
+
82
+
83
+ async deleteConversation(conversationId, userId) {
84
+ return await prisma.conversation.deleteMany({
85
+ where: {
86
+ id: conversationId,
87
+ userId,
88
+ },
89
+ })
90
+ }
91
+
92
+
93
+ async updateConversationTitle(conversationId, title) {
94
+ return await prisma.conversation.update({
95
+ where: { id: conversationId },
96
+ data: { title },
97
+ })
98
+ }
99
+
100
+ parseContent(content) {
101
+ try {
102
+ return JSON.parse(content)
103
+ } catch (error) {
104
+ return content
105
+ }
106
+ }
107
+
108
+
109
+ formatMessagesForAI(messages) {
110
+ return messages.map((msg) => ({
111
+ role: msg.role,
112
+ content: typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content)
113
+ }))
114
+ }
115
+
116
+
117
+ }