@dubeyvishal/orbital-cli 1.0.4 → 1.0.5
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/package.json +8 -10
- package/server/prisma/migrations/20260105143219_test_migration/migration.sql +7 -0
- package/server/prisma/migrations/20260105151026_authentication/migration.sql +78 -0
- package/server/prisma/migrations/20260114105919_add_devicecode_conversation_message/migration.sql +50 -0
- package/server/prisma/migrations/migration_lock.toml +3 -0
- package/server/prisma/schema.prisma +117 -0
- package/server/{ai → src/cli/ai}/googleService.js +4 -5
- package/server/{chat → src/cli/chat}/chat-with-ai-agent.js +43 -50
- package/server/{chat → src/cli/chat}/chat-with-ai-tools.js +70 -83
- package/server/{chat → src/cli/chat}/chat-with-ai.js +57 -69
- package/server/{commands → src/cli/commands}/General/openApp.js +13 -8
- package/server/{commands → src/cli/commands}/ai/wakeUp.js +18 -20
- package/server/{commands → src/cli/commands}/auth/aboutMe.js +3 -2
- package/server/{commands → src/cli/commands}/auth/login.js +35 -12
- package/server/{commands → src/cli/commands}/auth/logout.js +1 -1
- package/server/src/cli/commands/config/setkey.js +26 -0
- package/server/{main.js → src/cli/main.js} +1 -1
- package/server/src/cli/utils/apiClient.js +66 -0
- package/server/{config → src/config}/agentConfig.js +22 -17
- package/server/src/config/api.js +22 -0
- package/server/src/config/env.js +86 -0
- package/server/{config → src/config}/toolConfig.js +7 -0
- package/server/src/controllers/aiController.js +58 -0
- package/server/src/controllers/cliController.js +77 -0
- package/server/src/db/prisma.js +3 -0
- package/server/src/index.js +108 -0
- package/server/src/lib/auth.js +37 -0
- package/server/src/lib/credentialStore.js +47 -0
- package/server/src/lib/db.js +18 -0
- package/server/src/lib/dbHealth.js +106 -0
- package/server/src/lib/orbitalConfig.js +192 -0
- package/server/{utils → src/lib}/token.js +8 -14
- package/server/src/middleware/auth.js +39 -0
- package/server/src/middleware/errorHandler.js +11 -0
- package/server/src/prisma/migrations/20260107093841_device_flow/migration.sql +94 -0
- package/server/src/prisma/migrations/migration_lock.toml +3 -0
- package/server/src/prisma/schema.prisma +115 -0
- package/server/src/routes/authRoutes.js +14 -0
- package/server/src/routes/cliRoutes.js +18 -0
- package/server/src/service/chatService.js +156 -0
- package/server/src/services/aiService.js +10 -0
- package/server/src/services/chatService.js +1 -0
- package/server/src/types/express.d.ts +19 -0
- package/server/commands/config/setkey.js +0 -19
- package/server/config/env.js +0 -20
- package/server/utils/apiClient.js +0 -40
- package/server/utils/chatServiceClient.js +0 -73
- package/server/utils/orbitalConfig.js +0 -44
- /package/server/{commands → src/cli/commands}/General/playSong.js +0 -0
- /package/server/{commands → src/cli/commands}/General/searchYoutube.js +0 -0
- /package/server/{generalApp → src/cli/generalApp}/Apps.js +0 -0
- /package/server/{config → src/config}/googleConfig.js +0 -0
|
@@ -11,17 +11,17 @@ import {
|
|
|
11
11
|
import yoctoSpinner from "yocto-spinner";
|
|
12
12
|
import { marked } from "marked";
|
|
13
13
|
import { markedTerminal } from "marked-terminal";
|
|
14
|
-
import {
|
|
15
|
-
import { ChatServiceClient as ChatService } from "../utils/chatServiceClient.js";
|
|
16
|
-
import { getStoredToken } from "../utils/token.js";
|
|
17
|
-
|
|
14
|
+
import { getStoredToken } from "../../lib/token.js";
|
|
18
15
|
import {
|
|
19
16
|
availableTools,
|
|
20
17
|
enableTools,
|
|
21
18
|
getEnabledTools,
|
|
22
19
|
getEnabledToolNames,
|
|
23
20
|
resetTools,
|
|
24
|
-
} from "
|
|
21
|
+
} from "../../config/toolConfig.js";
|
|
22
|
+
import { apiRequestSafe } from "../utils/apiClient.js";
|
|
23
|
+
import { AIService } from "../ai/googleService.js";
|
|
24
|
+
import { requireGeminiApiKey } from "../../lib/orbitalConfig.js";
|
|
25
25
|
|
|
26
26
|
marked.use(
|
|
27
27
|
markedTerminal({
|
|
@@ -42,9 +42,6 @@ marked.use(
|
|
|
42
42
|
})
|
|
43
43
|
);
|
|
44
44
|
|
|
45
|
-
let aiService;
|
|
46
|
-
const chatService = new ChatService();
|
|
47
|
-
|
|
48
45
|
const getUserFromToken = async () => {
|
|
49
46
|
const token = await getStoredToken();
|
|
50
47
|
|
|
@@ -54,28 +51,20 @@ const getUserFromToken = async () => {
|
|
|
54
51
|
|
|
55
52
|
const spinner = yoctoSpinner({ text: "Authenticating..." }).start();
|
|
56
53
|
|
|
57
|
-
let user;
|
|
58
54
|
try {
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
Authorization: `Bearer ${token.access_token}`
|
|
62
|
-
}
|
|
63
|
-
});
|
|
55
|
+
const result = await apiRequestSafe("/api/cli/me");
|
|
56
|
+
const user = result?.user;
|
|
64
57
|
|
|
65
|
-
if (!
|
|
66
|
-
|
|
58
|
+
if (!user) {
|
|
59
|
+
spinner.error("User not found");
|
|
60
|
+
throw new Error("User not found. Please login again");
|
|
67
61
|
}
|
|
68
|
-
const data = await response.json();
|
|
69
|
-
user = data?.user;
|
|
70
62
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
63
|
+
spinner.success(`Welcome back, ${user.name}!`);
|
|
64
|
+
return user;
|
|
65
|
+
} finally {
|
|
66
|
+
spinner.stop();
|
|
75
67
|
}
|
|
76
|
-
|
|
77
|
-
spinner.success(`Welcome back, ${user.name}!`);
|
|
78
|
-
return user;
|
|
79
68
|
};
|
|
80
69
|
|
|
81
70
|
const selectTools = async () => {
|
|
@@ -132,17 +121,18 @@ const selectTools = async () => {
|
|
|
132
121
|
console.log(toolBox);
|
|
133
122
|
}
|
|
134
123
|
|
|
135
|
-
return selectedTools
|
|
124
|
+
return selectedTools;
|
|
136
125
|
};
|
|
137
126
|
|
|
138
127
|
const initConversation = async (userId, conversationId = null, mode = "tool") => {
|
|
139
128
|
const spinner = yoctoSpinner({ text: "Loading conversation..." }).start();
|
|
129
|
+
const result = await apiRequestSafe("/api/cli/conversations/init", {
|
|
130
|
+
method: "POST",
|
|
131
|
+
body: { conversationId, mode },
|
|
132
|
+
});
|
|
140
133
|
|
|
141
|
-
const conversation =
|
|
142
|
-
|
|
143
|
-
conversationId,
|
|
144
|
-
mode
|
|
145
|
-
);
|
|
134
|
+
const conversation = result?.conversation;
|
|
135
|
+
const messages = result?.messages || [];
|
|
146
136
|
|
|
147
137
|
spinner.success("Conversation Loaded");
|
|
148
138
|
|
|
@@ -168,9 +158,9 @@ const initConversation = async (userId, conversationId = null, mode = "tool") =>
|
|
|
168
158
|
|
|
169
159
|
console.log(conversationInfo);
|
|
170
160
|
|
|
171
|
-
if (
|
|
161
|
+
if (messages.length > 0) {
|
|
172
162
|
console.log(chalk.yellow("Previous Messages:\n"));
|
|
173
|
-
displayMessages(
|
|
163
|
+
displayMessages(messages);
|
|
174
164
|
}
|
|
175
165
|
|
|
176
166
|
return conversation;
|
|
@@ -206,54 +196,52 @@ const displayMessages = (messages) => {
|
|
|
206
196
|
const updateConversationTitle = async (conversationId, userInput, messageCount) => {
|
|
207
197
|
if (messageCount === 1) {
|
|
208
198
|
const title = userInput.slice(0, 50) + (userInput.length > 50 ? "..." : "");
|
|
209
|
-
await
|
|
199
|
+
await apiRequestSafe(`/api/cli/conversations/${conversationId}/title`, {
|
|
200
|
+
method: "PATCH",
|
|
201
|
+
body: { title },
|
|
202
|
+
});
|
|
210
203
|
}
|
|
211
204
|
};
|
|
212
205
|
|
|
213
206
|
const saveMessage = async (conversationId, role, content) => {
|
|
214
|
-
return await
|
|
207
|
+
return await apiRequestSafe("/api/cli/messages", {
|
|
208
|
+
method: "POST",
|
|
209
|
+
body: { conversationId, role, content },
|
|
210
|
+
});
|
|
215
211
|
};
|
|
216
212
|
|
|
217
|
-
const getAIResponse = async (conversationId) => {
|
|
213
|
+
const getAIResponse = async (conversationId, toolIds = []) => {
|
|
218
214
|
const spinner = yoctoSpinner({ text: "AI is thinking..." }).start();
|
|
219
|
-
|
|
220
|
-
const dbMessages = await chatService.getMessages(conversationId);
|
|
221
|
-
const aiMessages = chatService.formatMessageForAI(dbMessages);
|
|
222
|
-
|
|
223
|
-
const tools = getEnabledTools();
|
|
224
|
-
|
|
225
215
|
let fullResponse = "";
|
|
226
|
-
let isFirstChunk = true;
|
|
227
216
|
const toolCallsDetected = [];
|
|
228
217
|
|
|
229
218
|
try {
|
|
230
|
-
const
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
if (isFirstChunk) {
|
|
234
|
-
spinner.stop();
|
|
235
|
-
console.log("\n");
|
|
236
|
-
console.log(chalk.green.bold("Assistant: "));
|
|
237
|
-
console.log(chalk.gray("-".repeat(60)));
|
|
238
|
-
isFirstChunk = false;
|
|
239
|
-
}
|
|
240
|
-
fullResponse += chunk;
|
|
241
|
-
},
|
|
242
|
-
tools,
|
|
243
|
-
(toolCall) => {
|
|
244
|
-
toolCallsDetected.push(toolCall);
|
|
245
|
-
}
|
|
219
|
+
const messageResult = await apiRequestSafe(
|
|
220
|
+
`/api/cli/messages?conversationId=${encodeURIComponent(conversationId)}`,
|
|
221
|
+
{ method: "GET" }
|
|
246
222
|
);
|
|
247
223
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
224
|
+
const messages = Array.isArray(messageResult?.messages) ? messageResult.messages : [];
|
|
225
|
+
const aiMessages = messages.map((m) => ({ role: m.role, content: m.content }));
|
|
226
|
+
|
|
227
|
+
// Ensure the API key is present in env before any tools are initialized.
|
|
228
|
+
await requireGeminiApiKey();
|
|
229
|
+
|
|
230
|
+
// Ensure tool state matches what the user selected.
|
|
231
|
+
resetTools();
|
|
232
|
+
if (Array.isArray(toolIds)) enableTools(toolIds);
|
|
233
|
+
|
|
234
|
+
const tools = getEnabledTools();
|
|
235
|
+
const aiService = new AIService();
|
|
236
|
+
const result = await aiService.sendMessage(aiMessages, null, tools);
|
|
237
|
+
|
|
238
|
+
spinner.stop();
|
|
239
|
+
console.log("\n");
|
|
240
|
+
console.log(chalk.green.bold("Assistant: "));
|
|
241
|
+
console.log(chalk.gray("-".repeat(60)));
|
|
242
|
+
|
|
243
|
+
fullResponse = result?.content || "";
|
|
244
|
+
if (Array.isArray(result?.toolCalls)) toolCallsDetected.push(...result.toolCalls);
|
|
257
245
|
|
|
258
246
|
if (toolCallsDetected.length > 0) {
|
|
259
247
|
console.log("\n");
|
|
@@ -305,14 +293,14 @@ const getAIResponse = async (conversationId) => {
|
|
|
305
293
|
console.log(chalk.gray("-".repeat(60)));
|
|
306
294
|
console.log("\n");
|
|
307
295
|
|
|
308
|
-
return
|
|
296
|
+
return fullResponse.trim();
|
|
309
297
|
} catch (error) {
|
|
310
298
|
spinner.error("Failed to get AI response");
|
|
311
299
|
throw error;
|
|
312
300
|
}
|
|
313
301
|
};
|
|
314
302
|
|
|
315
|
-
const chatLoop = async (conversation) => {
|
|
303
|
+
const chatLoop = async (conversation, selectedToolIds = []) => {
|
|
316
304
|
const enabledToolNames = getEnabledToolNames();
|
|
317
305
|
|
|
318
306
|
const helpText = [
|
|
@@ -381,25 +369,24 @@ const chatLoop = async (conversation) => {
|
|
|
381
369
|
);
|
|
382
370
|
|
|
383
371
|
await saveMessage(conversation.id, "user", userInput);
|
|
384
|
-
const
|
|
372
|
+
const messageResult = await apiRequestSafe(
|
|
373
|
+
`/api/cli/messages?conversationId=${encodeURIComponent(conversation.id)}`,
|
|
374
|
+
{ method: "GET" }
|
|
375
|
+
);
|
|
385
376
|
|
|
386
|
-
const aiResponse = await getAIResponse(conversation.id);
|
|
377
|
+
const aiResponse = await getAIResponse(conversation.id, selectedToolIds);
|
|
387
378
|
await saveMessage(conversation.id, "assistant", aiResponse);
|
|
388
379
|
|
|
389
|
-
await updateConversationTitle(
|
|
380
|
+
await updateConversationTitle(
|
|
381
|
+
conversation.id,
|
|
382
|
+
userInput,
|
|
383
|
+
messageResult?.messages?.length || 0
|
|
384
|
+
);
|
|
390
385
|
}
|
|
391
386
|
};
|
|
392
387
|
|
|
393
388
|
export const startToolChat = async (conversationId) => {
|
|
394
389
|
try {
|
|
395
|
-
if (!process.env.GOOGLE_GENERATIVE_AI_API_KEY) {
|
|
396
|
-
throw new Error(
|
|
397
|
-
"Gemini API key is not set. Run: orbital setkey <your-gemini-api-key>"
|
|
398
|
-
);
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
aiService = new AIService();
|
|
402
|
-
|
|
403
390
|
intro(
|
|
404
391
|
boxen(chalk.bold.cyan("Orbital AI - Tool Calling Mode"), {
|
|
405
392
|
padding: 1,
|
|
@@ -410,11 +397,11 @@ export const startToolChat = async (conversationId) => {
|
|
|
410
397
|
|
|
411
398
|
const user = await getUserFromToken();
|
|
412
399
|
|
|
413
|
-
await selectTools();
|
|
400
|
+
const selectedToolIds = await selectTools();
|
|
414
401
|
|
|
415
402
|
const conversation = await initConversation(user.id, conversationId, "tool");
|
|
416
403
|
|
|
417
|
-
await chatLoop(conversation);
|
|
404
|
+
await chatLoop(conversation, selectedToolIds);
|
|
418
405
|
|
|
419
406
|
resetTools();
|
|
420
407
|
outro(chalk.green("Thanks for using tools"));
|
|
@@ -4,10 +4,10 @@ import {text , isCancel , cancel , intro , outro }from "@clack/prompts";
|
|
|
4
4
|
import yoctoSpinner from "yocto-spinner";
|
|
5
5
|
import {marked} from "marked";
|
|
6
6
|
import {markedTerminal} from "marked-terminal";
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
|
|
7
|
+
import {getStoredToken} from "../../lib/token.js";
|
|
8
|
+
import { apiRequestSafe } from "../utils/apiClient.js";
|
|
9
|
+
import { AIService } from "../ai/googleService.js";
|
|
10
|
+
import { requireGeminiApiKey } from "../../lib/orbitalConfig.js";
|
|
11
11
|
|
|
12
12
|
marked.use(
|
|
13
13
|
markedTerminal({
|
|
@@ -28,9 +28,6 @@ marked.use(
|
|
|
28
28
|
})
|
|
29
29
|
)
|
|
30
30
|
|
|
31
|
-
let aiService;
|
|
32
|
-
const chatService = new ChatService();
|
|
33
|
-
|
|
34
31
|
const getUserFromToken = async()=>{
|
|
35
32
|
const token = await getStoredToken()
|
|
36
33
|
if(!token?.access_token){
|
|
@@ -38,37 +35,29 @@ const getUserFromToken = async()=>{
|
|
|
38
35
|
}
|
|
39
36
|
|
|
40
37
|
const spinner = yoctoSpinner({text: "Authenticating..."}).start();
|
|
41
|
-
|
|
42
|
-
let user;
|
|
43
38
|
try {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
39
|
+
const result = await apiRequestSafe("/api/cli/me");
|
|
40
|
+
const user = result?.user;
|
|
41
|
+
if(!user){
|
|
42
|
+
spinner.error("User not found");
|
|
43
|
+
throw new Error("User not found. Please login again");
|
|
47
44
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
const data = await response.json();
|
|
53
|
-
user = data?.user;
|
|
54
|
-
if (!user) throw new Error("User not found");
|
|
55
|
-
} catch(err) {
|
|
56
|
-
spinner.error("Authentication failed");
|
|
57
|
-
throw new Error("User not found or connection failed. Please login again.");
|
|
45
|
+
spinner.success(`Welcome back , ${user.name}!`);
|
|
46
|
+
return user;
|
|
47
|
+
} finally {
|
|
48
|
+
spinner.stop();
|
|
58
49
|
}
|
|
59
|
-
|
|
60
|
-
spinner.success(`Welcome back , ${user.name}!`);
|
|
61
|
-
return user;
|
|
62
50
|
}
|
|
63
51
|
|
|
64
52
|
const initConversation = async(userId , conversationId = null , mode = "chat")=>{
|
|
65
53
|
const spinner = yoctoSpinner({text : "Loading conservation ..."}).start();
|
|
66
54
|
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
-
conversationId ,
|
|
70
|
-
|
|
71
|
-
|
|
55
|
+
const result = await apiRequestSafe("/api/cli/conversations/init", {
|
|
56
|
+
method: "POST",
|
|
57
|
+
body: { conversationId, mode },
|
|
58
|
+
});
|
|
59
|
+
const conversation = result?.conversation;
|
|
60
|
+
const messages = result?.messages || [];
|
|
72
61
|
spinner.success("Conversation Loaded");
|
|
73
62
|
|
|
74
63
|
const conversationInfo = boxen(
|
|
@@ -84,9 +73,9 @@ const initConversation = async(userId , conversationId = null , mode = "chat")=>
|
|
|
84
73
|
);
|
|
85
74
|
console.log(conversationInfo);
|
|
86
75
|
|
|
87
|
-
if(
|
|
76
|
+
if(messages.length > 0){
|
|
88
77
|
console.log(chalk.yellow("Previous Messsages: \n"));
|
|
89
|
-
displayMessages(
|
|
78
|
+
displayMessages(messages);
|
|
90
79
|
}
|
|
91
80
|
|
|
92
81
|
return conversation ;
|
|
@@ -120,7 +109,10 @@ const displayMessages = (messages) => {
|
|
|
120
109
|
};
|
|
121
110
|
|
|
122
111
|
const saveMessage = async(conversationId , role , content) =>{
|
|
123
|
-
return await
|
|
112
|
+
return await apiRequestSafe("/api/cli/messages", {
|
|
113
|
+
method: "POST",
|
|
114
|
+
body: { conversationId, role, content },
|
|
115
|
+
});
|
|
124
116
|
}
|
|
125
117
|
|
|
126
118
|
const getAIResponse = async(conversationId)=>{
|
|
@@ -129,40 +121,34 @@ const getAIResponse = async(conversationId)=>{
|
|
|
129
121
|
color: "cyan"
|
|
130
122
|
}).start();
|
|
131
123
|
|
|
132
|
-
const dbMessages = await chatService.getMessages(conversationId);
|
|
133
|
-
const aiMessages = chatService.formatMessageForAI(dbMessages);
|
|
134
|
-
|
|
135
124
|
let fullResponse = "";
|
|
136
|
-
let isFirstChunk = true ;
|
|
137
125
|
try{
|
|
138
|
-
const
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
const header = chalk.green.bold("Assistent: ");
|
|
143
|
-
console.log(header);
|
|
144
|
-
console.log(chalk.gray("-".repeat(60)));
|
|
145
|
-
isFirstChunk = false ;
|
|
146
|
-
}
|
|
147
|
-
fullResponse += chunk ;
|
|
148
|
-
});
|
|
126
|
+
const messageResult = await apiRequestSafe(
|
|
127
|
+
`/api/cli/messages?conversationId=${encodeURIComponent(conversationId)}`,
|
|
128
|
+
{ method: "GET" }
|
|
129
|
+
);
|
|
149
130
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
isFirstChunk = false;
|
|
157
|
-
}
|
|
131
|
+
const messages = Array.isArray(messageResult?.messages) ? messageResult.messages : [];
|
|
132
|
+
const aiMessages = messages.map((m) => ({ role: m.role, content: m.content }));
|
|
133
|
+
|
|
134
|
+
await requireGeminiApiKey();
|
|
135
|
+
const aiService = new AIService();
|
|
136
|
+
const result = await aiService.sendMessage(aiMessages);
|
|
158
137
|
|
|
138
|
+
spinner.stop();
|
|
139
|
+
console.log("\n");
|
|
140
|
+
const header = chalk.green.bold("Assistent: ");
|
|
141
|
+
console.log(header);
|
|
142
|
+
console.log(chalk.gray("-".repeat(60)));
|
|
143
|
+
|
|
144
|
+
fullResponse = result?.content || "";
|
|
159
145
|
console.log("\n");
|
|
160
146
|
const renderMarkdown = marked.parse(fullResponse);
|
|
161
147
|
console.log(renderMarkdown);
|
|
162
148
|
console.log(chalk.gray("-".repeat(60)));
|
|
163
149
|
console.log("\n");
|
|
164
150
|
|
|
165
|
-
return
|
|
151
|
+
return fullResponse ;
|
|
166
152
|
}
|
|
167
153
|
catch(error){
|
|
168
154
|
spinner.error("Failed to get AI response");
|
|
@@ -173,7 +159,10 @@ const getAIResponse = async(conversationId)=>{
|
|
|
173
159
|
const updateConversationTitle = async(conversationId , userInput , messageCount)=>{
|
|
174
160
|
if(messageCount ===1){
|
|
175
161
|
const title = userInput.slice(0,50) + (userInput.length > 50 ? "..." : "");
|
|
176
|
-
await
|
|
162
|
+
await apiRequestSafe(`/api/cli/conversations/${conversationId}/title`, {
|
|
163
|
+
method: "PATCH",
|
|
164
|
+
body: { title },
|
|
165
|
+
});
|
|
177
166
|
}
|
|
178
167
|
}
|
|
179
168
|
|
|
@@ -223,12 +212,19 @@ const chatLoop = async(conversation)=>{
|
|
|
223
212
|
break ;
|
|
224
213
|
}
|
|
225
214
|
await saveMessage(conversation.id , "user" , userInput);
|
|
226
|
-
const
|
|
215
|
+
const messageResult = await apiRequestSafe(
|
|
216
|
+
`/api/cli/messages?conversationId=${encodeURIComponent(conversation.id)}`,
|
|
217
|
+
{ method: "GET" }
|
|
218
|
+
);
|
|
227
219
|
|
|
228
220
|
const aiResponse = await getAIResponse(conversation.id);
|
|
229
|
-
|
|
221
|
+
await saveMessage(conversation.id , "assistant" , aiResponse);
|
|
230
222
|
|
|
231
|
-
|
|
223
|
+
await updateConversationTitle(
|
|
224
|
+
conversation.id ,
|
|
225
|
+
userInput ,
|
|
226
|
+
messageResult?.messages?.length || 0
|
|
227
|
+
)
|
|
232
228
|
}
|
|
233
229
|
}
|
|
234
230
|
|
|
@@ -236,14 +232,6 @@ const chatLoop = async(conversation)=>{
|
|
|
236
232
|
|
|
237
233
|
export const startChat = async(mode="chat" , conversationId = null)=>{
|
|
238
234
|
try{
|
|
239
|
-
if (!process.env.GOOGLE_GENERATIVE_AI_API_KEY) {
|
|
240
|
-
throw new Error(
|
|
241
|
-
"Gemini API key is not set. Run: orbital setkey <your-gemini-api-key>"
|
|
242
|
-
);
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
aiService = new AIService();
|
|
246
|
-
|
|
247
235
|
intro(
|
|
248
236
|
boxen(chalk.bold.cyan("Orbital AI Chat") , {
|
|
249
237
|
padding: 1 ,
|
|
@@ -1,21 +1,26 @@
|
|
|
1
1
|
import chalk from "chalk";
|
|
2
2
|
import { Command } from "commander";
|
|
3
3
|
import yoctoSpinner from "yocto-spinner";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
4
|
+
import { getStoredToken } from "../../../lib/token.js";
|
|
5
|
+
import { select } from "@clack/prompts";
|
|
6
|
+
import {openGithub , openLinkedin , openLeetcode , openGmail , openWhatsApp} from "../../../cli/generalApp/Apps.js"
|
|
7
|
+
import { apiRequestSafe } from "../../utils/apiClient.js";
|
|
6
8
|
|
|
7
9
|
const openAppAction = async () => {
|
|
10
|
+
const token = await getStoredToken();
|
|
11
|
+
|
|
12
|
+
if (!token?.access_token) {
|
|
13
|
+
console.log(chalk.red("Not Authenticated. Please login."));
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
|
|
8
17
|
const spinner = yoctoSpinner({ text: "Fetching user information..." });
|
|
9
18
|
spinner.start();
|
|
10
19
|
|
|
11
20
|
let user;
|
|
12
21
|
try {
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
user = res.user;
|
|
16
|
-
} catch (err) {
|
|
17
|
-
console.log(chalk.red(err.message));
|
|
18
|
-
return;
|
|
22
|
+
const result = await apiRequestSafe("/api/cli/me");
|
|
23
|
+
user = result?.user;
|
|
19
24
|
} finally {
|
|
20
25
|
spinner.stop();
|
|
21
26
|
}
|
|
@@ -1,38 +1,36 @@
|
|
|
1
1
|
import chalk from "chalk";
|
|
2
2
|
import {Command} from "commander";
|
|
3
3
|
import yoctoSpinner from "yocto-spinner";
|
|
4
|
-
import {getStoredToken} from "
|
|
5
|
-
|
|
4
|
+
import {getStoredToken} from "../../../lib/token.js"
|
|
6
5
|
import {select} from "@clack/prompts";
|
|
7
|
-
import {startChat} from "
|
|
8
|
-
import {startToolChat} from "
|
|
9
|
-
import {startAgentChat} from "
|
|
6
|
+
import {startChat} from "../../../cli/chat/chat-with-ai.js";
|
|
7
|
+
import {startToolChat} from "../../../cli/chat/chat-with-ai-tools.js";
|
|
8
|
+
import {startAgentChat} from "../../../cli/chat/chat-with-ai-agent.js";
|
|
9
|
+
import { apiRequestSafe } from "../../utils/apiClient.js";
|
|
10
|
+
import { requireGeminiApiKey } from "../../../lib/orbitalConfig.js";
|
|
10
11
|
|
|
11
12
|
|
|
12
13
|
const wakeUpAction = async()=>{
|
|
14
|
+
try {
|
|
15
|
+
await requireGeminiApiKey();
|
|
16
|
+
} catch {
|
|
17
|
+
console.log(chalk.red("Gemini API key not set. Run: orbital set-key <API_KEY>"));
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
|
|
13
21
|
const token = await getStoredToken();
|
|
14
22
|
if(!token?.access_token){
|
|
15
23
|
console.log(chalk.red("Not Authenticated. please login"))
|
|
16
24
|
return ;
|
|
17
25
|
}
|
|
18
26
|
|
|
27
|
+
const spinner = yoctoSpinner({text: "Fetching user information ..."})
|
|
28
|
+
spinner.start()
|
|
29
|
+
|
|
19
30
|
let user;
|
|
20
31
|
try{
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
Authorization: `Bearer ${token.access_token}`
|
|
24
|
-
}
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
if (!response.ok) {
|
|
28
|
-
throw new Error("Failed to authenticate.");
|
|
29
|
-
}
|
|
30
|
-
const data = await response.json();
|
|
31
|
-
user = data?.user;
|
|
32
|
-
|
|
33
|
-
if (!user) throw new Error("User not found");
|
|
34
|
-
} catch(err) {
|
|
35
|
-
console.log(chalk.red("Failed to authenticate with server."));
|
|
32
|
+
const result = await apiRequestSafe("/api/cli/me");
|
|
33
|
+
user = result?.user;
|
|
36
34
|
}
|
|
37
35
|
finally{
|
|
38
36
|
spinner.stop();
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import chalk from "chalk";
|
|
2
2
|
import { Command } from "commander";
|
|
3
|
-
import { requireAuth } from "
|
|
3
|
+
import { requireAuth } from "../../../lib/token.js";
|
|
4
|
+
import { API_BASE } from "../../../config/api.js";
|
|
4
5
|
|
|
5
|
-
const DEFAULT_SERVER_URL =
|
|
6
|
+
const DEFAULT_SERVER_URL = API_BASE;
|
|
6
7
|
|
|
7
8
|
export const whoAmIAction = async (cmdOptions = {})=>{
|
|
8
9
|
const token = await requireAuth();
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import "../../../config/env.js";
|
|
1
2
|
import { cancel, confirm, intro, outro, isCancel } from "@clack/prompts";
|
|
2
3
|
import chalk from "chalk";
|
|
3
4
|
import { Command } from "commander";
|
|
@@ -10,25 +11,37 @@ import { createAuthClient } from "better-auth/client";
|
|
|
10
11
|
import { deviceAuthorizationClient } from "better-auth/client/plugins";
|
|
11
12
|
import { logger } from "better-auth";
|
|
12
13
|
import { fileURLToPath } from "url";
|
|
13
|
-
import { getStoredToken, isTokenExpired, storeToken ,TOKEN_FILE } from "
|
|
14
|
+
import { getStoredToken, isTokenExpired, storeToken ,TOKEN_FILE } from "../../../lib/token.js";
|
|
15
|
+
import { API_BASE } from "../../../config/api.js";
|
|
16
|
+
import { apiRequestSafe } from "../../utils/apiClient.js";
|
|
17
|
+
import { requireGeminiApiKey } from "../../../lib/orbitalConfig.js";
|
|
14
18
|
|
|
15
19
|
|
|
16
20
|
|
|
17
21
|
const __filename = fileURLToPath(import.meta.url);
|
|
18
22
|
const __dirname = path.dirname(__filename);
|
|
19
23
|
|
|
20
|
-
const URL =
|
|
21
|
-
|
|
24
|
+
const URL = API_BASE;
|
|
25
|
+
|
|
26
|
+
const resolveClientId = async (cliClientId) => {
|
|
27
|
+
const resolved = (cliClientId || "").trim();
|
|
28
|
+
if (resolved.length > 0) return resolved;
|
|
29
|
+
|
|
30
|
+
const response = await apiRequestSafe("/auth/github/client-id", {
|
|
31
|
+
method: "GET",
|
|
32
|
+
requireAuth: false,
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
const clientId = typeof response?.client_id === "string" ? response.client_id.trim() : "";
|
|
36
|
+
return clientId.length > 0 ? clientId : undefined;
|
|
37
|
+
};
|
|
22
38
|
|
|
23
39
|
|
|
24
40
|
export const loginAction = async (cmdOptions) => {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
"Run: orbital setkey <your-gemini-api-key>\nThen run: orbital login",
|
|
30
|
-
),
|
|
31
|
-
);
|
|
41
|
+
try {
|
|
42
|
+
await requireGeminiApiKey();
|
|
43
|
+
} catch {
|
|
44
|
+
console.log(chalk.red("Gemini API key not set. Run: orbital set-key <API_KEY>"));
|
|
32
45
|
process.exit(1);
|
|
33
46
|
}
|
|
34
47
|
|
|
@@ -43,7 +56,17 @@ export const loginAction = async (cmdOptions) => {
|
|
|
43
56
|
});
|
|
44
57
|
|
|
45
58
|
const serverUrl = options.serverUrl || URL;
|
|
46
|
-
const clientId = options.clientId
|
|
59
|
+
const clientId = await resolveClientId(options.clientId);
|
|
60
|
+
|
|
61
|
+
if (!clientId) {
|
|
62
|
+
console.error(chalk.red("GitHub OAuth client ID is not available from the server."));
|
|
63
|
+
console.log(
|
|
64
|
+
chalk.gray(
|
|
65
|
+
"Make sure the backend is deployed and configured with GITHUB_CLIENT_ID.",
|
|
66
|
+
),
|
|
67
|
+
);
|
|
68
|
+
process.exit(1);
|
|
69
|
+
}
|
|
47
70
|
|
|
48
71
|
intro(chalk.bold("Auth CLI Login"));
|
|
49
72
|
|
|
@@ -238,5 +261,5 @@ const pollForToken = async (
|
|
|
238
261
|
export const login = new Command("login")
|
|
239
262
|
.description("Login to Better Auth")
|
|
240
263
|
.option("--server-url <url>", "The Better Auth server URL", URL)
|
|
241
|
-
.option("--client-id <id>", "The OAuth client ID"
|
|
264
|
+
.option("--client-id <id>", "The OAuth client ID")
|
|
242
265
|
.action(loginAction);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import chalk from "chalk";
|
|
2
2
|
import { cancel, confirm, intro, outro, isCancel } from "@clack/prompts";
|
|
3
3
|
import { Command } from "commander";
|
|
4
|
-
import { clearStoredToken, getStoredToken } from "
|
|
4
|
+
import { clearStoredToken, getStoredToken } from "../../../lib/token.js";
|
|
5
5
|
|
|
6
6
|
export const logoutAction = async()=>{
|
|
7
7
|
intro(chalk.bold("Logout"));
|