@dubeyvishal/orbital-cli 1.6.14 → 1.6.16

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.
@@ -1,145 +1,84 @@
1
1
  import chalk from "chalk";
2
- import { Command } from "commander";
3
- import yoctoSpinner from "yocto-spinner";
4
- import { getStoredToken } from "../../../lib/token.js";
5
- import { select, password, isCancel, cancel } from "@clack/prompts";
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";
2
+ import {Command} from "commander";
3
+ import yoctoSpinner from "yocto-spinner";
4
+ import {getStoredToken} from "../../../lib/token.js"
5
+ import {select} from "@clack/prompts";
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
9
  import { apiRequestSafe } from "../../utils/apiClient.js";
10
- import {
11
- getApiKey,
12
- setApiKey,
13
- getSelectedModel,
14
- saveSelectedModel,
15
- } from "../../../lib/orbitalConfig.js";
16
- import {
17
- AI_PROVIDERS,
18
- getModelSelectOptions,
19
- parseModelChoice,
20
- getModelDisplayName,
21
- } from "../../../config/aiConfig.js";
10
+ import { requireGeminiApiKey } from "../../../lib/orbitalConfig.js";
22
11
 
23
- const wakeUpAction = async () => {
24
- const token = await getStoredToken();
25
- if (!token?.access_token) {
26
- console.log(chalk.red("Not Authenticated. Please run 'orbital login' first."));
27
- return;
28
- }
29
12
 
30
- const spinner = yoctoSpinner({ text: "Fetching user information..." });
31
- spinner.start();
32
-
33
- let user;
34
- try {
35
- const result = await apiRequestSafe("/api/cli/me");
36
- user = result?.user;
37
- } finally {
38
- spinner.stop();
39
- }
40
-
41
- if (!user) {
42
- console.log(chalk.red("User not found. Please log in again with 'orbital login'."));
43
- return;
44
- }
45
-
46
- console.log(chalk.green(`Welcome back, ${user.name}! \n`));
47
-
48
- // 1. Ask user to select the AI model FIRST
49
- const savedModel = await getSelectedModel();
50
- const modelOptions = getModelSelectOptions();
51
- const defaultModelValue = `${savedModel.provider}:${savedModel.model}`;
52
-
53
- const selectedModelChoice = await select({
54
- message: "Select an AI Model:",
55
- options: modelOptions,
56
- initialValue: modelOptions.some((o) => o.value === defaultModelValue)
57
- ? defaultModelValue
58
- : undefined,
59
- });
60
-
61
- if (isCancel(selectedModelChoice)) {
62
- cancel("Model selection cancelled.");
63
- return;
64
- }
65
-
66
- const { provider, model } = parseModelChoice(selectedModelChoice);
67
- await saveSelectedModel({ provider, model });
68
-
69
- // 2. Ensure API key is configured for the chosen model/provider
70
- let apiKey = await getApiKey(provider);
71
- if (!apiKey) {
72
- const provInfo = AI_PROVIDERS[provider];
73
- console.log(
74
- chalk.yellow(
75
- `\n${provInfo?.name || provider} API key is required. (Obtain one at: ${provInfo?.docsUrl || "provider portal"})`
76
- )
77
- );
78
-
79
- const enteredKey = await password({
80
- message: `Enter your ${provInfo?.name || provider} API key:`,
81
- validate(value) {
82
- if (!value || !value.trim()) return "API key cannot be empty";
83
- },
84
- });
85
-
86
- if (isCancel(enteredKey)) {
87
- cancel("Operation cancelled.");
88
- return;
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;
89
19
  }
90
20
 
91
- await setApiKey(provider, enteredKey);
92
- console.log(chalk.green(`✔ ${provInfo?.name || provider} API key saved securely.\n`));
93
- }
94
-
95
- console.log(
96
- chalk.cyan(`Active AI Model: ${chalk.bold(getModelDisplayName(provider, model))}\n`)
97
- );
98
-
99
- // 3. Mode selection
100
- const choice = await select({
101
- message: "Select an Option",
102
- options: [
103
- {
104
- value: "chat",
105
- label: "Chat",
106
- hint: "Simple chat with AI",
107
- },
108
- {
109
- value: "tool",
110
- label: "Tool Calling",
111
- hint: "Chat with tools and code execution",
112
- },
113
- {
114
- value: "agent",
115
- label: "Agentic Mode",
116
- hint: "Fullstack application generation agent",
117
- },
118
- ],
119
- });
120
-
121
- if (isCancel(choice)) {
122
- cancel("Operation cancelled.");
123
- return;
124
- }
125
-
126
- const modelConfig = { provider, model };
127
-
128
- switch (choice) {
129
- case "chat":
130
- await startChat("chat", null, modelConfig);
131
- break;
132
- case "tool":
133
- await startToolChat(modelConfig);
134
- break;
135
- case "agent":
136
- await startAgentChat(modelConfig);
137
- break;
138
- }
139
- };
140
-
141
- export const wakeUp = new Command("wakeup")
142
- .description("Wake up the AI")
143
- .alias("wake-up")
144
- .alias("wakup")
145
- .action(wakeUpAction);
21
+ const token = await getStoredToken();
22
+ if(!token?.access_token){
23
+ console.log(chalk.red("Not Authenticated. please login"))
24
+ return ;
25
+ }
26
+
27
+ const spinner = yoctoSpinner({text: "Fetching user information ..."})
28
+ spinner.start()
29
+
30
+ let user;
31
+ try{
32
+ const result = await apiRequestSafe("/api/cli/me");
33
+ user = result?.user;
34
+ }
35
+ finally{
36
+ spinner.stop();
37
+ }
38
+
39
+ if(!user){
40
+ console.log(chalk.red("User not found."))
41
+ return ;
42
+ }
43
+
44
+ console.log(chalk.green(`Welcome back, ${user.name}! \n`));
45
+
46
+ const choice = await select({
47
+ message : "Select an Option",
48
+ options : [
49
+ {
50
+ value : "chat",
51
+ label: "Chat",
52
+ hint : "Simple chat with AI"
53
+ },
54
+ {
55
+ value : "tool",
56
+ label: "Tool Calling",
57
+ hint : "Chat with tools (Google Search , Code Execution"
58
+ },
59
+ {
60
+ value : "agent",
61
+ label: "Agentic Mode",
62
+ hint : "Advanced AI Agent"
63
+ },
64
+ ]
65
+ });
66
+
67
+ switch(choice){
68
+ case "chat":
69
+ await startChat("chat");
70
+ break ;
71
+ case "tool":
72
+ await startToolChat();
73
+ break ;
74
+ case "agent":
75
+ await startAgentChat();
76
+ break ;
77
+ }
78
+ }
79
+
80
+ export const wakeUp = new Command("wakeup").
81
+ description("Wake up the AI").
82
+ alias("wake-up").
83
+ alias("wakup").
84
+ action(wakeUpAction)
@@ -11,6 +11,7 @@ import { fileURLToPath } from "url";
11
11
  import { getStoredToken, isTokenExpired, storeToken ,TOKEN_FILE } from "../../../lib/token.js";
12
12
  import { API_BASE } from "../../../config/api.js";
13
13
  import { apiRequestSafe } from "../../utils/apiClient.js";
14
+ import { requireGeminiApiKey } from "../../../lib/orbitalConfig.js";
14
15
 
15
16
 
16
17
  const __filename = fileURLToPath(import.meta.url);
@@ -92,7 +93,12 @@ const resolveClientId = async (cliClientId) => {
92
93
 
93
94
 
94
95
  export const loginAction = async (cmdOptions) => {
95
-
96
+ try {
97
+ await requireGeminiApiKey();
98
+ } catch {
99
+ console.log(chalk.red("Gemini API key not set. Run: orbital set-key <API_KEY>"));
100
+ process.exit(1);
101
+ }
96
102
 
97
103
  const schema = z.object({
98
104
  serverUrl: z.string().optional(),
@@ -1,58 +1,12 @@
1
1
  import { Command } from "commander";
2
2
  import chalk from "chalk";
3
- import { select, password, isCancel, cancel } from "@clack/prompts";
4
- import { setApiKey, normalizeProviderName } from "../../../lib/orbitalConfig.js";
3
+ import { setGeminiApiKey } from "../../../lib/orbitalConfig.js";
5
4
  import { getCredentialServiceName } from "../../../lib/credentialStore.js";
6
- import { AI_PROVIDERS } from "../../../config/aiConfig.js";
7
5
 
8
- const setKeyAction = async (apiKeyArg, cmdOptions) => {
6
+ const setKeyAction = async (apiKey) => {
9
7
  try {
10
- let provider = cmdOptions.provider;
11
- let apiKey = apiKeyArg;
12
-
13
- // Interactive mode if key was not supplied via command line argument
14
- if (!apiKey) {
15
- if (!provider) {
16
- const provChoice = await select({
17
- message: "Select AI Provider to configure API key for:",
18
- options: [
19
- { value: "gemini", label: "Google Gemini", hint: "AI Studio API key" },
20
- { value: "openai", label: "OpenAI", hint: "platform.openai.com key" },
21
- { value: "grok", label: "Grok (xAI)", hint: "console.x.ai key" },
22
- ],
23
- });
24
-
25
- if (isCancel(provChoice)) {
26
- cancel("Operation cancelled.");
27
- return;
28
- }
29
- provider = provChoice;
30
- }
31
-
32
- const provInfo = AI_PROVIDERS[normalizeProviderName(provider)];
33
- const enteredKey = await password({
34
- message: `Enter your ${provInfo?.name || provider} API key:`,
35
- validate(value) {
36
- if (!value || !value.trim()) return "API key cannot be empty";
37
- },
38
- });
39
-
40
- if (isCancel(enteredKey)) {
41
- cancel("Operation cancelled.");
42
- return;
43
- }
44
-
45
- apiKey = enteredKey;
46
- }
47
-
48
- const norm = normalizeProviderName(provider || "gemini");
49
- const provInfo = AI_PROVIDERS[norm];
50
-
51
- await setApiKey(norm, apiKey);
52
-
53
- console.log(
54
- chalk.green(`\n✔ ${provInfo?.name || norm} API key saved successfully.`)
55
- );
8
+ await setGeminiApiKey(apiKey);
9
+ console.log(chalk.green("Gemini API key saved."));
56
10
  console.log(
57
11
  chalk.gray(
58
12
  `Stored securely in your OS credential manager (service: ${getCredentialServiceName()}).`
@@ -65,13 +19,8 @@ const setKeyAction = async (apiKeyArg, cmdOptions) => {
65
19
  };
66
20
 
67
21
  export const setkey = new Command("set-key")
68
- .description("Store your AI provider API key securely in keytar (Gemini, OpenAI, Grok)")
69
- .argument("[API_KEY]", "Your AI provider API key")
70
- .option(
71
- "-p, --provider <provider>",
72
- "AI provider: gemini (default), openai, or grok",
73
- "gemini"
74
- )
22
+ .description("Store your Gemini API key securely (keytar)")
23
+ .argument("<API_KEY>", "Your Gemini API key")
75
24
  .alias("set")
76
25
  .alias("setkey")
77
26
  .action(setKeyAction);
@@ -13,10 +13,10 @@ import {launch} from "./commands/General/openApp.js"
13
13
  import {search} from "./commands/General/searchYoutube.js"
14
14
  import {play} from "./commands/General/playSong.js"
15
15
  import { createRequire } from "module";
16
+
16
17
  const require = createRequire(import.meta.url);
17
18
  const packageJson = require("../../../package.json");
18
19
 
19
-
20
20
  const main = async()=>{
21
21
 
22
22
  console.log(
@@ -2,5 +2,5 @@ import "./env.js";
2
2
 
3
3
  export const config = {
4
4
  googleApiKey : process.env.GOOGLE_GENERATIVE_AI_API_KEY || "",
5
- model : process.env.ORBITAL_MODEL || "gemini-2.5-flash"
5
+ model : process.env.ORBITAL_MODEL || "gemini-3.5-flash-lite"
6
6
  }
@@ -1,19 +1,13 @@
1
1
  import { google } from "@ai-sdk/google";
2
2
  import chalk from "chalk";
3
- import {
4
- normalizeProviderName,
5
- requireApiKeySync,
6
- hasApiKeySync,
7
- } from "../lib/orbitalConfig.js";
3
+ import { requireGeminiApiKeySync } from "../lib/orbitalConfig.js";
8
4
 
9
5
  export const availableTools = [
10
- // Google Gemini Native Tools
11
6
  {
12
7
  id: "google_search",
13
8
  name: "Google Search",
14
9
  description:
15
10
  "Access the latest information using Google Search. Useful for current events, news, and real-time information",
16
- provider: "gemini",
17
11
  getTool: () => google.tools.googleSearch({}),
18
12
  enabled: false,
19
13
  },
@@ -22,7 +16,6 @@ export const availableTools = [
22
16
  name: "Code Execution",
23
17
  description:
24
18
  "Generate and execute Python code to perform calculations, solve problems or provide accurate information",
25
- provider: "gemini",
26
19
  getTool: () => google.tools.codeExecution({}),
27
20
  enabled: false,
28
21
  },
@@ -31,41 +24,45 @@ export const availableTools = [
31
24
  name: "URL Context",
32
25
  description:
33
26
  "Provide specific URLs that you want the model to analyse directly from the prompt. Supports up to 20 URLs per request.",
34
- provider: "gemini",
35
27
  getTool: () => google.tools.urlContext({}),
36
28
  enabled: false,
37
29
  },
38
30
  ];
39
31
 
40
- export const getToolsForProvider = (provider = "gemini") => {
41
- const norm = normalizeProviderName(provider);
42
- return availableTools.filter(
43
- (tool) => tool.provider === "all" || tool.provider === norm
44
- );
45
- };
46
-
47
- export const getEnabledTools = (provider = "gemini") => {
48
- const norm = normalizeProviderName(provider);
32
+ export const getEnabledTools = () => {
49
33
  const tools = {};
50
34
 
51
35
  try {
52
- const providerTools = getToolsForProvider(norm);
36
+ const enabledToolCount = availableTools.filter((t) => t.enabled).length;
37
+ if (enabledToolCount > 0 && !process.env.GOOGLE_GENERATIVE_AI_API_KEY) {
38
+
39
+ requireGeminiApiKeySync();
40
+ }
53
41
 
54
- for (const toolConfig of providerTools) {
42
+ for (const toolConfig of availableTools) {
55
43
  if (toolConfig.enabled) {
56
- if (toolConfig.provider === "gemini" && !hasApiKeySync("gemini")) {
57
- requireApiKeySync("gemini");
58
- }
59
44
  tools[toolConfig.id] = toolConfig.getTool();
60
45
  }
61
46
  }
62
47
 
48
+ if (Object.keys(tools).length > 0) {
49
+ console.log(
50
+ chalk.gray(`[DEBUG] Enabled tools: ${Object.keys(tools).join(", ")}`)
51
+ );
52
+ } else {
53
+ console.log(chalk.yellow(`[DEBUG] No tools enabled`));
54
+ }
55
+
63
56
  return Object.keys(tools).length > 0 ? tools : undefined;
64
57
  } catch (error) {
65
58
  console.error(
66
59
  chalk.red(`[ERROR] Failed to initialize tools:`),
67
60
  error?.message || error
68
61
  );
62
+ console.error(
63
+ chalk.yellow(`Make sure you have @ai-sdk/google version 2.0+ installed`)
64
+ );
65
+ console.error(chalk.yellow(`Run: npm install @ai-sdk/google@latest`));
69
66
  return undefined;
70
67
  }
71
68
  };
@@ -75,27 +72,49 @@ export const toggleTool = (toolId) => {
75
72
 
76
73
  if (tool) {
77
74
  tool.enabled = !tool.enabled;
75
+ console.log(
76
+ chalk.gray(`[DEBUG] Tool ${toolId} toggled to ${tool.enabled}`)
77
+ );
78
78
  return tool.enabled;
79
79
  }
80
80
 
81
+ console.log(chalk.red(`[DEBUG] Tool ${toolId} not found`));
81
82
  return false;
82
83
  };
83
84
 
84
85
  export const toogleTool = toggleTool;
85
86
 
86
87
  export const enableTools = (toolIds = []) => {
88
+ console.log(chalk.gray(`[DEBUG] enableTools called with:`), toolIds);
89
+
87
90
  availableTools.forEach((tool) => {
91
+ const wasEnabled = tool.enabled;
88
92
  tool.enabled = toolIds.includes(tool.id);
93
+
94
+ if (tool.enabled !== wasEnabled) {
95
+ console.log(
96
+ chalk.gray(`[DEBUG] ${tool.id}: ${wasEnabled} -> ${tool.enabled}`)
97
+ );
98
+ }
89
99
  });
100
+
101
+ const enabledCount = availableTools.filter((t) => t.enabled).length;
102
+ console.log(
103
+ chalk.gray(
104
+ `[DEBUG] Total tools enabled: ${enabledCount} / ${availableTools.length}`
105
+ )
106
+ );
90
107
  };
91
108
 
92
109
  export const getEnabledToolNames = () => {
93
- return availableTools.filter((t) => t.enabled).map((t) => t.name);
110
+ const names = availableTools.filter((t) => t.enabled).map((t) => t.name);
111
+ console.log(chalk.gray(`[DEBUG] getEnabledToolNames returning:`), names);
112
+ return names;
94
113
  };
95
114
 
96
115
  export const resetTools = () => {
97
116
  availableTools.forEach((tool) => {
98
117
  tool.enabled = false;
99
118
  });
119
+ console.log(chalk.gray(`[DEBUG] All tools have been reset (disabled)`));
100
120
  };
101
-
@@ -7,7 +7,7 @@ const chatService = new ChatService();
7
7
 
8
8
  export const respond = async (req, res, next) => {
9
9
  try {
10
- const { conversationId, mode, toolIds, provider, model } = req.body || {};
10
+ const { conversationId, mode, toolIds } = req.body || {};
11
11
 
12
12
  if (!conversationId) {
13
13
  return res.status(400).json({ error: "conversationId is required" });
@@ -16,18 +16,16 @@ export const respond = async (req, res, next) => {
16
16
  const messages = await chatService.getMessages(conversationId);
17
17
  const aiMessages = chatService.formatMessageForAI(messages);
18
18
 
19
- const modelConfig = provider || model ? { provider, model } : null;
20
- const aiService = getAIService(modelConfig);
21
-
22
19
  let tools;
23
20
  if (mode === "tool") {
24
21
  resetTools();
25
22
  if (Array.isArray(toolIds)) {
26
23
  enableTools(toolIds);
27
24
  }
28
- tools = getEnabledTools(aiService.provider);
25
+ tools = getEnabledTools();
29
26
  }
30
27
 
28
+ const aiService = getAIService();
31
29
  const result = await aiService.sendMessage(aiMessages, null, tools);
32
30
 
33
31
  await chatService.addMessage(conversationId, "assistant", result.content);
@@ -36,7 +34,6 @@ export const respond = async (req, res, next) => {
36
34
  content: result.content,
37
35
  toolCalls: result.toolCalls || [],
38
36
  toolResults: result.toolResults || [],
39
- model: aiService.getDisplayName(),
40
37
  });
41
38
  } catch (error) {
42
39
  return next(error);
@@ -45,17 +42,16 @@ export const respond = async (req, res, next) => {
45
42
 
46
43
  export const generateAgentPlan = async (req, res, next) => {
47
44
  try {
48
- const { description, provider, model } = req.body || {};
45
+ const { description } = req.body || {};
49
46
 
50
47
  if (!description || typeof description !== "string") {
51
48
  return res.status(400).json({ error: "description is required" });
52
49
  }
53
50
 
54
- const modelConfig = provider || model ? { provider, model } : null;
55
- const aiService = getAIService(modelConfig);
51
+ const aiService = getAIService();
56
52
  const application = await generateApplicationPlan(description, aiService);
57
53
 
58
- return res.json({ application, model: aiService.getDisplayName() });
54
+ return res.json({ application });
59
55
  } catch (error) {
60
56
  return next(error);
61
57
  }
@@ -16,65 +16,32 @@ const loadKeytar = async () => {
16
16
  };
17
17
 
18
18
  export const getCredentialServiceName = () => ORBITAL_KEYTAR_SERVICE;
19
- export const getApiKeyAccountName = (provider = "gemini") => {
20
- const p = (provider || "gemini").toLowerCase().trim();
21
- if (p === "google" || p === "gemini") return "api-key-gemini";
22
- if (p === "openai") return "api-key-openai";
23
- if (p === "xai" || p === "grok") return "api-key-grok";
24
- return `api-key-${p}`;
25
- };
19
+ export const getApiKeyAccountName = () => ORBITAL_API_KEY_ACCOUNT;
26
20
 
27
- export const getStoredApiKey = async (provider = "gemini") => {
21
+ export const getStoredApiKey = async () => {
28
22
  const keytar = await loadKeytar();
29
- const account = getApiKeyAccountName(provider);
30
- let value = await keytar.getPassword(ORBITAL_KEYTAR_SERVICE, account);
31
-
32
- // Backward-compatibility for Gemini: fall back to legacy ORBITAL_API_KEY_ACCOUNT
33
- const p = (provider || "gemini").toLowerCase().trim();
34
- if (!value && (p === "gemini" || p === "google")) {
35
- value = await keytar.getPassword(
36
- ORBITAL_KEYTAR_SERVICE,
37
- ORBITAL_API_KEY_ACCOUNT
38
- );
39
- }
40
-
23
+ const value = await keytar.getPassword(
24
+ ORBITAL_KEYTAR_SERVICE,
25
+ ORBITAL_API_KEY_ACCOUNT
26
+ );
41
27
  return typeof value === "string" ? value.trim() : "";
42
28
  };
43
29
 
44
- export const storeApiKey = async (apiKey, provider = "gemini") => {
30
+ export const storeApiKey = async (apiKey) => {
45
31
  const trimmed = typeof apiKey === "string" ? apiKey.trim() : "";
46
32
  if (!trimmed) throw new Error("API key is required");
47
33
 
48
34
  const keytar = await loadKeytar();
49
- const account = getApiKeyAccountName(provider);
50
- await keytar.setPassword(ORBITAL_KEYTAR_SERVICE, account, trimmed);
51
-
52
- // For Gemini, also keep legacy account updated for backward compatibility
53
- const p = (provider || "gemini").toLowerCase().trim();
54
- if (p === "gemini" || p === "google") {
55
- await keytar.setPassword(
56
- ORBITAL_KEYTAR_SERVICE,
57
- ORBITAL_API_KEY_ACCOUNT,
58
- trimmed
59
- );
60
- }
61
-
35
+ await keytar.setPassword(
36
+ ORBITAL_KEYTAR_SERVICE,
37
+ ORBITAL_API_KEY_ACCOUNT,
38
+ trimmed
39
+ );
62
40
  return true;
63
41
  };
64
42
 
65
- export const deleteStoredApiKey = async (provider = "gemini") => {
43
+ export const deleteStoredApiKey = async () => {
66
44
  const keytar = await loadKeytar();
67
- const account = getApiKeyAccountName(provider);
68
- await keytar.deletePassword(ORBITAL_KEYTAR_SERVICE, account);
69
-
70
- const p = (provider || "gemini").toLowerCase().trim();
71
- if (p === "gemini" || p === "google") {
72
- await keytar.deletePassword(
73
- ORBITAL_KEYTAR_SERVICE,
74
- ORBITAL_API_KEY_ACCOUNT
75
- );
76
- }
77
-
45
+ await keytar.deletePassword(ORBITAL_KEYTAR_SERVICE, ORBITAL_API_KEY_ACCOUNT);
78
46
  return true;
79
47
  };
80
-