orbital-cli-agent 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.
- package/package.json +29 -0
- package/src/cli/ai/google-service.js +128 -0
- package/src/cli/api/api-client.js +115 -0
- package/src/cli/chat/chat-with-ai-agent.js +237 -0
- package/src/cli/chat/chat-with-ai-tool.js +371 -0
- package/src/cli/chat/chat-with-ai.js +267 -0
- package/src/cli/commands/ai/wakeup.js +61 -0
- package/src/cli/commands/auth/login.js +423 -0
- package/src/cli/main.js +52 -0
- package/src/config/agent.config.js +94 -0
- package/src/config/google.config.js +8 -0
- package/src/config/tool.config.js +107 -0
package/package.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "orbital-cli-agent",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "A CLI based AI Agent",
|
|
5
|
+
"main": "src/cli/main.js",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"orbital": "./src/cli/main.js"
|
|
9
|
+
},
|
|
10
|
+
"dependencies": {
|
|
11
|
+
"@ai-sdk/google": "^3.0.86",
|
|
12
|
+
"@clack/prompts": "^1.5.1",
|
|
13
|
+
"ai": "^6.0.214",
|
|
14
|
+
"better-auth": "^1.6.5",
|
|
15
|
+
"boxen": "^8.0.1",
|
|
16
|
+
"chalk": "^5.6.2",
|
|
17
|
+
"commander": "^15.0.0",
|
|
18
|
+
"dotenv": "^17.4.2",
|
|
19
|
+
"figlet": "^1.11.0",
|
|
20
|
+
"marked": "^15.0.12",
|
|
21
|
+
"marked-terminal": "^7.3.0",
|
|
22
|
+
"open": "^11.0.0",
|
|
23
|
+
"yocto-spinner": "^1.2.0",
|
|
24
|
+
"zod": "^4.4.3"
|
|
25
|
+
},
|
|
26
|
+
"files": [
|
|
27
|
+
"src"
|
|
28
|
+
]
|
|
29
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { google } from "@ai-sdk/google";
|
|
2
|
+
import { streamText, generateObject } from "ai";
|
|
3
|
+
import { config } from "../../config/google.config.js";
|
|
4
|
+
import chalk from "chalk";
|
|
5
|
+
|
|
6
|
+
export class AIService {
|
|
7
|
+
constructor() {
|
|
8
|
+
if (!config.googleApiKey) {
|
|
9
|
+
throw new Error("GOOGLE_API_KEY is not set in environment variables");
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
this.model = google(config.orbitalModel, {
|
|
13
|
+
apiKey: config.googleApiKey,
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Send a message and get streaming response
|
|
19
|
+
* @param {Array} messages - Array of message objects {role, content}
|
|
20
|
+
* @param {Function} onChunk - Callback for each text chunk
|
|
21
|
+
* @param {Object} tools - Optional tools object
|
|
22
|
+
* @param {Function} onToolCall - Callback for tool calls
|
|
23
|
+
* @returns {Promise<Object>} Full response with content, tool calls, and usage
|
|
24
|
+
*/
|
|
25
|
+
async sendMessage(messages, onChunk, tools = undefined, onToolCall = null) {
|
|
26
|
+
try {
|
|
27
|
+
const streamConfig = {
|
|
28
|
+
model: this.model,
|
|
29
|
+
messages: messages,
|
|
30
|
+
temperature: config.temperature,
|
|
31
|
+
maxTokens: config.maxTokens,
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
// Add tools if provided with maxSteps for multi-step tool calling
|
|
35
|
+
if (tools && Object.keys(tools).length > 0) {
|
|
36
|
+
streamConfig.tools = tools;
|
|
37
|
+
streamConfig.maxSteps = 5; // Allow up to 5 tool call steps
|
|
38
|
+
|
|
39
|
+
console.log(chalk.gray(`[DEBUG] Tools enabled: ${Object.keys(tools).join(', ')}`));
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const result = streamText(streamConfig);
|
|
43
|
+
|
|
44
|
+
let fullResponse = "";
|
|
45
|
+
|
|
46
|
+
// Stream text chunks
|
|
47
|
+
for await (const chunk of result.textStream) {
|
|
48
|
+
fullResponse += chunk;
|
|
49
|
+
if (onChunk) {
|
|
50
|
+
onChunk(chunk);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// IMPORTANT: Await the result to get access to steps, toolCalls, etc.
|
|
55
|
+
const fullResult = await result;
|
|
56
|
+
|
|
57
|
+
const toolCalls = [];
|
|
58
|
+
const toolResults = [];
|
|
59
|
+
|
|
60
|
+
// Collect tool calls from all steps (if they exist)
|
|
61
|
+
if (fullResult.steps && Array.isArray(fullResult.steps)) {
|
|
62
|
+
for (const step of fullResult.steps) {
|
|
63
|
+
if (step.toolCalls && step.toolCalls.length > 0) {
|
|
64
|
+
for (const toolCall of step.toolCalls) {
|
|
65
|
+
toolCalls.push(toolCall);
|
|
66
|
+
if (onToolCall) {
|
|
67
|
+
onToolCall(toolCall);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Collect tool results
|
|
73
|
+
if (step.toolResults && step.toolResults.length > 0) {
|
|
74
|
+
toolResults.push(...step.toolResults);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return {
|
|
80
|
+
content: fullResponse,
|
|
81
|
+
finishReason: fullResult.finishReason,
|
|
82
|
+
usage: fullResult.usage,
|
|
83
|
+
toolCalls,
|
|
84
|
+
toolResults,
|
|
85
|
+
steps: fullResult.steps,
|
|
86
|
+
};
|
|
87
|
+
} catch (error) {
|
|
88
|
+
console.error(chalk.red("AI Service Error:"), error.message);
|
|
89
|
+
console.error(chalk.red("Full error:"), error);
|
|
90
|
+
throw error;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Get a non-streaming response
|
|
96
|
+
* @param {Array} messages - Array of message objects
|
|
97
|
+
* @param {Object} tools - Optional tools
|
|
98
|
+
* @returns {Promise<string>} Response text
|
|
99
|
+
*/
|
|
100
|
+
async getMessage(messages, tools = undefined) {
|
|
101
|
+
let fullResponse = "";
|
|
102
|
+
const result = await this.sendMessage(messages, (chunk) => {
|
|
103
|
+
fullResponse += chunk;
|
|
104
|
+
}, tools);
|
|
105
|
+
return result.content;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Generate structured output using a Zod schema
|
|
110
|
+
* @param {Object} schema - Zod schema
|
|
111
|
+
* @param {string} prompt - Prompt for generation
|
|
112
|
+
* @returns {Promise<Object>} Parsed object matching the schema
|
|
113
|
+
*/
|
|
114
|
+
async generateStructured(schema, prompt) {
|
|
115
|
+
try {
|
|
116
|
+
const result = await generateObject({
|
|
117
|
+
model: this.model,
|
|
118
|
+
schema: schema,
|
|
119
|
+
prompt: prompt,
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
return result.object;
|
|
123
|
+
} catch (error) {
|
|
124
|
+
console.error(chalk.red("AI Structured Generation Error:"), error.message);
|
|
125
|
+
throw error;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import dotenv from "dotenv";
|
|
3
|
+
|
|
4
|
+
dotenv.config();
|
|
5
|
+
|
|
6
|
+
const URL = process.env.BETTER_AUTH_URL || "http://localhost:3005";
|
|
7
|
+
|
|
8
|
+
export async function getUserFromApi(accessToken) {
|
|
9
|
+
try {
|
|
10
|
+
const response = await fetch(`${URL}/api/me`, {
|
|
11
|
+
headers: {
|
|
12
|
+
Authorization: `Bearer ${accessToken}`,
|
|
13
|
+
},
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
if (!response.ok) {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const data = await response.json();
|
|
21
|
+
return data?.user || null;
|
|
22
|
+
} catch (error) {
|
|
23
|
+
console.error(chalk.red("Failed to fetch user session from server:"), error.message);
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export async function getOrCreateConversation(accessToken, conversationId, mode = "chat") {
|
|
29
|
+
try {
|
|
30
|
+
const response = await fetch(`${URL}/api/chat/conversations`, {
|
|
31
|
+
method: "POST",
|
|
32
|
+
headers: {
|
|
33
|
+
"Content-Type": "application/json",
|
|
34
|
+
Authorization: `Bearer ${accessToken}`,
|
|
35
|
+
},
|
|
36
|
+
body: JSON.stringify({ conversationId, mode }),
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
if (!response.ok) {
|
|
40
|
+
const errData = await response.json();
|
|
41
|
+
throw new Error(errData.error || "Failed to get or create conversation");
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return await response.json();
|
|
45
|
+
} catch (error) {
|
|
46
|
+
console.error(chalk.red("API Error (getOrCreateConversation):"), error.message);
|
|
47
|
+
throw error;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export async function addMessage(accessToken, conversationId, role, content) {
|
|
52
|
+
try {
|
|
53
|
+
const response = await fetch(`${URL}/api/chat/messages`, {
|
|
54
|
+
method: "POST",
|
|
55
|
+
headers: {
|
|
56
|
+
"Content-Type": "application/json",
|
|
57
|
+
Authorization: `Bearer ${accessToken}`,
|
|
58
|
+
},
|
|
59
|
+
body: JSON.stringify({ conversationId, role, content }),
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
if (!response.ok) {
|
|
63
|
+
const errData = await response.json();
|
|
64
|
+
throw new Error(errData.error || "Failed to add message");
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return await response.json();
|
|
68
|
+
} catch (error) {
|
|
69
|
+
console.error(chalk.red("API Error (addMessage):"), error.message);
|
|
70
|
+
throw error;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export async function getMessages(accessToken, conversationId) {
|
|
75
|
+
try {
|
|
76
|
+
const response = await fetch(`${URL}/api/chat/conversations/${conversationId}/messages`, {
|
|
77
|
+
headers: {
|
|
78
|
+
Authorization: `Bearer ${accessToken}`,
|
|
79
|
+
},
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
if (!response.ok) {
|
|
83
|
+
const errData = await response.json();
|
|
84
|
+
throw new Error(errData.error || "Failed to get messages");
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return await response.json();
|
|
88
|
+
} catch (error) {
|
|
89
|
+
console.error(chalk.red("API Error (getMessages):"), error.message);
|
|
90
|
+
throw error;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export async function updateTitle(accessToken, conversationId, title) {
|
|
95
|
+
try {
|
|
96
|
+
const response = await fetch(`${URL}/api/chat/conversations/${conversationId}`, {
|
|
97
|
+
method: "PUT",
|
|
98
|
+
headers: {
|
|
99
|
+
"Content-Type": "application/json",
|
|
100
|
+
Authorization: `Bearer ${accessToken}`,
|
|
101
|
+
},
|
|
102
|
+
body: JSON.stringify({ title }),
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
if (!response.ok) {
|
|
106
|
+
const errData = await response.json();
|
|
107
|
+
throw new Error(errData.error || "Failed to update title");
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return await response.json();
|
|
111
|
+
} catch (error) {
|
|
112
|
+
console.error(chalk.red("API Error (updateTitle):"), error.message);
|
|
113
|
+
throw error;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import boxen from "boxen";
|
|
3
|
+
import { text, isCancel, cancel, intro, outro, confirm } from "@clack/prompts";
|
|
4
|
+
import { AIService } from "../ai/google-service.js";
|
|
5
|
+
import { getStoredToken } from "../commands/auth/login.js";
|
|
6
|
+
import { generateApplication } from "../../config/agent.config.js";
|
|
7
|
+
import * as apiClient from "../api/api-client.js";
|
|
8
|
+
import path from "path";
|
|
9
|
+
|
|
10
|
+
const aiService = new AIService();
|
|
11
|
+
|
|
12
|
+
function getSmartOutputDir() {
|
|
13
|
+
if (process.env.ORBIT_OUTPUT_DIR) {
|
|
14
|
+
return path.resolve(process.env.ORBIT_OUTPUT_DIR);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const cwd = process.cwd();
|
|
18
|
+
const isInsideWorkspace = cwd.includes("CLI AI AGENT") || cwd.includes("cli-ai-agent");
|
|
19
|
+
|
|
20
|
+
if (isInsideWorkspace) {
|
|
21
|
+
const pathParts = cwd.split(path.sep);
|
|
22
|
+
const index = pathParts.findIndex(part =>
|
|
23
|
+
part.toLowerCase() === "cli ai agent" || part.toLowerCase() === "cli-ai-agent"
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
if (index !== -1) {
|
|
27
|
+
const parentDir = pathParts.slice(0, index).join(path.sep);
|
|
28
|
+
return path.join(parentDir, "orbit-apps");
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return path.join(cwd, "..", "orbit-apps");
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return cwd;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async function getUserFromToken() {
|
|
38
|
+
const token = await getStoredToken();
|
|
39
|
+
|
|
40
|
+
if (!token?.access_token) {
|
|
41
|
+
throw new Error("Not authenticated. Please run 'orbit login' first.");
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const user = await apiClient.getUserFromApi(token.access_token);
|
|
45
|
+
|
|
46
|
+
if (!user) {
|
|
47
|
+
throw new Error("User not found. Please login again.");
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
console.log(chalk.green(`\n✓ Welcome back, ${user.name}!\n`));
|
|
51
|
+
return { user, token };
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async function initConversation(token, userId, conversationId = null) {
|
|
55
|
+
const conversation = await apiClient.getOrCreateConversation(
|
|
56
|
+
token,
|
|
57
|
+
conversationId,
|
|
58
|
+
"agent"
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
const conversationInfo = boxen(
|
|
62
|
+
`${chalk.bold("Conversation")}: ${conversation.title}\n` +
|
|
63
|
+
`${chalk.gray("ID:")} ${conversation.id}\n` +
|
|
64
|
+
`${chalk.gray("Mode:")} ${chalk.magenta("Agent (Code Generator)")}\n` +
|
|
65
|
+
`${chalk.cyan("Target Directory:")} ${getSmartOutputDir()}`,
|
|
66
|
+
{
|
|
67
|
+
padding: 1,
|
|
68
|
+
margin: { top: 1, bottom: 1 },
|
|
69
|
+
borderStyle: "round",
|
|
70
|
+
borderColor: "magenta",
|
|
71
|
+
title: "🤖 Agent Mode",
|
|
72
|
+
titleAlignment: "center",
|
|
73
|
+
}
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
console.log(conversationInfo);
|
|
77
|
+
|
|
78
|
+
return conversation;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async function saveMessage(token, conversationId, role, content) {
|
|
82
|
+
return await apiClient.addMessage(token, conversationId, role, content);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
async function agentLoop(token, conversation) {
|
|
86
|
+
const helpBox = boxen(
|
|
87
|
+
`${chalk.cyan.bold("What can the agent do?")}\n\n` +
|
|
88
|
+
`${chalk.gray('• Generate complete applications from descriptions')}\n` +
|
|
89
|
+
`${chalk.gray('• Create all necessary files and folders')}\n` +
|
|
90
|
+
`${chalk.gray('• Include setup instructions and commands')}\n` +
|
|
91
|
+
`${chalk.gray('• Generate production-ready code')}\n\n` +
|
|
92
|
+
`${chalk.yellow.bold("Examples:")}\n` +
|
|
93
|
+
`${chalk.white('• "Build a todo app with React and Tailwind"')}\n` +
|
|
94
|
+
`${chalk.white('• "Create a REST API with Express and MongoDB"')}\n` +
|
|
95
|
+
`${chalk.white('• "Make a weather app using OpenWeatherMap API"')}\n\n` +
|
|
96
|
+
`${chalk.gray('Type "exit" to end the session')}`,
|
|
97
|
+
{
|
|
98
|
+
padding: 1,
|
|
99
|
+
margin: { bottom: 1 },
|
|
100
|
+
borderStyle: "round",
|
|
101
|
+
borderColor: "cyan",
|
|
102
|
+
title: "💡 Agent Instructions",
|
|
103
|
+
}
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
console.log(helpBox);
|
|
107
|
+
|
|
108
|
+
while (true) {
|
|
109
|
+
const userInput = await text({
|
|
110
|
+
message: chalk.magenta("🤖 What would you like to build?"),
|
|
111
|
+
placeholder: "Describe your application...",
|
|
112
|
+
validate(value) {
|
|
113
|
+
if (!value || value.trim().length === 0) {
|
|
114
|
+
return "Description cannot be empty";
|
|
115
|
+
}
|
|
116
|
+
if (value.trim().length < 10) {
|
|
117
|
+
return "Please provide more details (at least 10 characters)";
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
if (isCancel(userInput)) {
|
|
123
|
+
console.log(chalk.yellow("\n👋 Agent session cancelled\n"));
|
|
124
|
+
process.exit(0);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (userInput.toLowerCase() === "exit") {
|
|
128
|
+
console.log(chalk.yellow("\n👋 Agent session ended\n"));
|
|
129
|
+
break;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const userBox = boxen(chalk.white(userInput), {
|
|
133
|
+
padding: 1,
|
|
134
|
+
margin: { top: 1, bottom: 1 },
|
|
135
|
+
borderStyle: "round",
|
|
136
|
+
borderColor: "blue",
|
|
137
|
+
title: "👤 Your Request",
|
|
138
|
+
titleAlignment: "left",
|
|
139
|
+
});
|
|
140
|
+
console.log(userBox);
|
|
141
|
+
|
|
142
|
+
// Save user message
|
|
143
|
+
await saveMessage(token, conversation.id, "user", userInput);
|
|
144
|
+
|
|
145
|
+
try {
|
|
146
|
+
// Generate application using structured output
|
|
147
|
+
const outputDir = getSmartOutputDir();
|
|
148
|
+
const result = await generateApplication(
|
|
149
|
+
userInput,
|
|
150
|
+
aiService,
|
|
151
|
+
outputDir
|
|
152
|
+
);
|
|
153
|
+
|
|
154
|
+
if (result && result.success) {
|
|
155
|
+
// Save successful generation details
|
|
156
|
+
const responseMessage = `Generated application: ${result.folderName}\n` +
|
|
157
|
+
`Files created: ${result.files.length}\n` +
|
|
158
|
+
`Location: ${result.appDir}\n\n` +
|
|
159
|
+
`Setup commands:\n${result.commands.join('\n')}`;
|
|
160
|
+
|
|
161
|
+
await saveMessage(token, conversation.id, "assistant", responseMessage);
|
|
162
|
+
|
|
163
|
+
// Ask if user wants to generate another app
|
|
164
|
+
const continuePrompt = await confirm({
|
|
165
|
+
message: chalk.cyan("Would you like to generate another application?"),
|
|
166
|
+
initialValue: false,
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
if (isCancel(continuePrompt) || !continuePrompt) {
|
|
170
|
+
console.log(chalk.yellow("\n👋 Great! Check your new application.\n"));
|
|
171
|
+
break;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
} else {
|
|
175
|
+
throw new Error("Generation returned no result");
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
} catch (error) {
|
|
179
|
+
console.log(chalk.red(`\n❌ Error: ${error.message}\n`));
|
|
180
|
+
|
|
181
|
+
await saveMessage(token, conversation.id, "assistant", `Error: ${error.message}`);
|
|
182
|
+
|
|
183
|
+
const retry = await confirm({
|
|
184
|
+
message: chalk.cyan("Would you like to try again?"),
|
|
185
|
+
initialValue: true,
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
if (isCancel(retry) || !retry) {
|
|
189
|
+
break;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
export async function startAgentChat(conversationId = null) {
|
|
196
|
+
try {
|
|
197
|
+
intro(
|
|
198
|
+
boxen(
|
|
199
|
+
chalk.bold.magenta("🤖 Orbit AI - Agent Mode\n\n") +
|
|
200
|
+
chalk.gray("Autonomous Application Generator"),
|
|
201
|
+
{
|
|
202
|
+
padding: 1,
|
|
203
|
+
borderStyle: "double",
|
|
204
|
+
borderColor: "magenta",
|
|
205
|
+
}
|
|
206
|
+
)
|
|
207
|
+
);
|
|
208
|
+
|
|
209
|
+
const { user, token } = await getUserFromToken();
|
|
210
|
+
|
|
211
|
+
// Warning about file system access
|
|
212
|
+
const shouldContinue = await confirm({
|
|
213
|
+
message: chalk.yellow("⚠️ The agent will create files and folders in the current directory. Continue?"),
|
|
214
|
+
initialValue: true,
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
if (isCancel(shouldContinue) || !shouldContinue) {
|
|
218
|
+
cancel(chalk.yellow("Agent mode cancelled"));
|
|
219
|
+
process.exit(0);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
const conversation = await initConversation(token.access_token, user.id, conversationId);
|
|
223
|
+
await agentLoop(token.access_token, conversation);
|
|
224
|
+
|
|
225
|
+
outro(chalk.green.bold("\n✨ Thanks for using Agent Mode!"));
|
|
226
|
+
|
|
227
|
+
} catch (error) {
|
|
228
|
+
const errorBox = boxen(chalk.red(`❌ Error: ${error.message}`), {
|
|
229
|
+
padding: 1,
|
|
230
|
+
margin: 1,
|
|
231
|
+
borderStyle: "round",
|
|
232
|
+
borderColor: "red",
|
|
233
|
+
});
|
|
234
|
+
console.log(errorBox);
|
|
235
|
+
process.exit(1);
|
|
236
|
+
}
|
|
237
|
+
}
|