pulse-cli-divakar 0.0.0-stage → 1.0.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/package.json CHANGED
@@ -1,6 +1,55 @@
1
- {
2
- "name": "pulse-cli-divakar",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
1
+ {
2
+ "name": "pulse-cli-divakar",
3
+ "version": "1.0.1",
4
+ "main": "src/index.js",
5
+ "bin": {
6
+ "pulse": "./src/cli/main.js"
7
+ },
8
+ "type": "module",
9
+ "scripts": {
10
+ "test": "echo \"Error: no test specified\" && exit 1",
11
+ "dev": "nodemon src/index.js",
12
+ "start": "node src/index.js",
13
+ "db:generate": "prisma generate",
14
+ "db:deploy": "prisma migrate deploy"
15
+ },
16
+ "author": "",
17
+ "license": "MIT",
18
+ "dependencies": {
19
+ "@ai-sdk/google": "^4.0.104",
20
+ "@clack/prompts": "^1.8.1",
21
+ "@neondatabase/serverless": "^1.2.0",
22
+ "@prisma/adapter-neon": "^7.10.1",
23
+ "@prisma/client": "^7.10.1",
24
+ "ai": "^7.0.143",
25
+ "better-auth": "^1.7.10",
26
+ "boxen": "^9.0.0",
27
+ "chalk": "^6.0.1",
28
+ "commander": "^15.0.0",
29
+ "cors": "^2.8.6",
30
+ "dotenv": "^18.0.8",
31
+ "express": "^5.3.0",
32
+ "figlet": "^1.12.0",
33
+ "marked": "^15.0.12",
34
+ "marked-terminal": "^7.3.0",
35
+ "open": "^11.0.4",
36
+ "yocto-spinner": "^1.2.2",
37
+ "zod": "^4.6.7"
38
+ },
39
+ "keywords": [
40
+ "pulse",
41
+ "cli",
42
+ "ai",
43
+ "developer-tools"
44
+ ],
45
+ "description": "Pulse CLI — an AI-powered command-line application",
46
+ "devDependencies": {
47
+ "prisma": "^7.10.1"
48
+ },
49
+ "files": [
50
+ "src/cli",
51
+ "src/lib",
52
+ "src/config"
53
+ ]
54
+
55
+ }
@@ -0,0 +1,127 @@
1
+ import {config} from "../../config/google.config.js"
2
+ import {google} from "@ai-sdk/google"
3
+ import {generateText, Output, streamText} from "ai"
4
+ import chalk from "chalk"
5
+
6
+
7
+ export class AIService{
8
+ constructor(){
9
+ if(!config.googleApiKey){
10
+ throw new Error("Google_API_KEY is not present in env.")
11
+ }
12
+ this.model=google(config.model,{
13
+ apiKey:config.googleApiKey
14
+ })
15
+ }
16
+
17
+ // send message in chunk like sendMessage(messages,(chunk)=>{
18
+ // console.log(chunk})
19
+
20
+ async sendMessage(messages,onChunk,tools=undefined,onToolCall=null){
21
+ try {
22
+ const streamConfig={
23
+ model:this.model,
24
+ messages:messages
25
+ }
26
+
27
+ if(tools && Object.keys(tools).length>0){
28
+ streamConfig.tools=tools;
29
+ streamConfig.maxSteps=5;
30
+
31
+ console.log(chalk.gray(`[Debug] Tools enabled : ${Object.keys(tools).join(",")}`))
32
+ }
33
+
34
+ const result=streamText(streamConfig)
35
+
36
+
37
+
38
+ let fullResponse=""
39
+
40
+ for await (const chunk of result.textStream){
41
+ fullResponse+=chunk;
42
+ if(onChunk){
43
+ // callback()
44
+ onChunk(chunk)
45
+ }
46
+ }
47
+
48
+ const fullResult=result;
49
+
50
+
51
+ const toolCalls=[]
52
+ const toolResults=[]
53
+
54
+
55
+ if(fullResult.steps && Array.isArray(fullResult.steps)){
56
+ for(const step of fullResult.steps){
57
+ if(step.toolCalls && step.toolCalls.length>0){
58
+ for(const toolCall of step.toolCalls){
59
+ toolCalls.push(toolCall);
60
+ if(onToolCall){
61
+ onToolCall(toolCall)
62
+ }
63
+ }
64
+ }
65
+ if(step.toolResults && step.toolResults.length>0){
66
+ toolResults.push(...step.toolResults)
67
+ }
68
+ }
69
+ }
70
+
71
+ /**
72
+ * {
73
+ textStream: AsyncIterable, // Streaming text chunks
74
+ text: Promise, // Complete generated text
75
+ finishReason: Promise, // Generation kyu finish hui
76
+ usage: Promise, // Token usage information
77
+ response: Promise, // Response metadata
78
+ request: { ... }, // Request information
79
+ more properties...
80
+ }
81
+ */
82
+
83
+ return{
84
+ content:fullResponse,
85
+ finishResponse:fullResult.finishReason,
86
+ usage:fullResult.usage,
87
+ toolCalls,
88
+ toolResults,
89
+ steps:fullResult.steps
90
+ }
91
+
92
+ } catch (error) {
93
+ console.error(chalk.red("AI Service Error:"),error.message)
94
+ throw error;
95
+ }
96
+ }
97
+
98
+ // Send message in a single go
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
+ async generateStructured(schema,promt){
110
+ try {
111
+ const result=await generateText({
112
+ model:this.model,
113
+ output:Output.object({
114
+ schema:schema
115
+ }),
116
+ prompt:promt
117
+ })
118
+ return result.object
119
+ } catch (error) {
120
+ console.log(chalk.red("AI Structured Generation Failed:"),error.message)
121
+ throw error;
122
+ }
123
+ }
124
+
125
+ }
126
+
127
+
@@ -0,0 +1,57 @@
1
+ import chalk from "chalk";
2
+ import boxen from "boxen"
3
+ import { text,isCancel,cancel,intro,outro } from "@clack/prompts";
4
+ import yoctoSpinner from "yocto-spinner";
5
+ import {marked} from "marked"
6
+ import {markedTerminal} from "marked-terminal"
7
+ import { chatLoop, getUserFromToken, initConversation } from "./utils/chataiutils.js";
8
+
9
+
10
+ marked.use(
11
+ markedTerminal({
12
+ // Styling options for terminal output
13
+ code: chalk.cyan,
14
+ blockquote: chalk.gray.italic,
15
+ heading: chalk.green.bold,
16
+ firstHeading: chalk.magenta.underline.bold,
17
+ hr: chalk.reset,
18
+ listitem: chalk.reset,
19
+ list: chalk.reset,
20
+ paragraph: chalk.reset,
21
+ strong: chalk.bold,
22
+ em: chalk.italic,
23
+ codespan: chalk.yellow.bgBlack,
24
+ del: chalk.dim.gray.strikethrough,
25
+ link: chalk.blue.underline,
26
+ href: chalk.blue.underline,
27
+ })
28
+ );
29
+
30
+
31
+
32
+ export async function startChat(mode="chat",conversationId=null) {
33
+ try {
34
+ intro(
35
+ boxen(chalk.bold.cyan("Pulse AI Chat"),{
36
+ padding:1,
37
+ borderStyle:"double",
38
+ borderColor:"green"
39
+ })
40
+ )
41
+
42
+ const user=await getUserFromToken()
43
+ const conversation=await initConversation(user.id,conversationId,mode)
44
+ await chatLoop(conversation);
45
+
46
+ outro(chalk.green("šŸ«‚ Thanks For Chatting"))
47
+ } catch (error) {
48
+ const errorBox = boxen(chalk.red(`āŒ Error: ${error.message}`), {
49
+ padding: 1,
50
+ margin: 1,
51
+ borderStyle: "round",
52
+ borderColor: "red",
53
+ });
54
+ console.log(errorBox);
55
+ process.exit(1);
56
+ }
57
+ }
@@ -0,0 +1,206 @@
1
+ import chalk from "chalk";
2
+ import boxen from "boxen";
3
+ import {
4
+ text,
5
+ isCancel,
6
+ cancel,
7
+ intro,
8
+ outro,
9
+ box,
10
+ multiselect,
11
+ confirm,
12
+ } from "@clack/prompts";
13
+ import yoctoSpinner from "yocto-spinner";
14
+ import { marked } from "marked";
15
+ import { markedTerminal } from "marked-terminal";
16
+ import { AIService } from "../ai/google-service.js";
17
+ import { ChatService } from "../../service/chat.service.js";
18
+ import { getStoredToken } from "../../lib/token.js";
19
+ import { prisma } from "../../lib/db.js";
20
+ import { getUserFromToken, saveMessage } from "./utils/chataiutils.js";
21
+ import { generateApplication } from "../../config/agent-config.js";
22
+
23
+ const aiService = new AIService();
24
+ const chatService = new ChatService();
25
+
26
+ async function initConversation(userId, conversationId = null) {
27
+ const conversation = await chatService.getOrCreateConversation(
28
+ userId,
29
+ conversationId,
30
+ "agent",
31
+ );
32
+
33
+ const conversationInfo = boxen(
34
+ `${chalk.bold("Conversation")}: ${conversation.title}\n` +
35
+ `${chalk.gray("ID:")} ${conversation.id}\n` +
36
+ `${chalk.gray("Mode:")} ${chalk.magenta("Agent (Code Generator)")}\n` +
37
+ `${chalk.cyan("Working Directory:")} ${process.cwd()}`,
38
+ {
39
+ padding: 1,
40
+ margin: { top: 1, bottom: 1 },
41
+ borderStyle: "round",
42
+ borderColor: "magenta",
43
+ title: "šŸ¤– Agent Mode",
44
+ titleAlignment: "center",
45
+ },
46
+ );
47
+
48
+ console.log(conversationInfo);
49
+
50
+ return conversation;
51
+ }
52
+
53
+ export async function startAgentChat(conversationId = null) {
54
+ try {
55
+ intro(
56
+ boxen(
57
+ chalk.bold.magenta("šŸ¤– Pulse AI - Agent Mode\n\n") +
58
+ chalk.gray("Autonomous Application Generator"),
59
+ {
60
+ padding: 1,
61
+ borderStyle: "double",
62
+ borderColor: "magenta",
63
+ },
64
+ ),
65
+ );
66
+
67
+ const user = await getUserFromToken();
68
+
69
+ const shouldContinue = await confirm({
70
+ message: chalk.yellow(
71
+ "āš ļø The agent will create files and folders in the current directory. Continue?",
72
+ ),
73
+ initialValue: true,
74
+ });
75
+
76
+ if (isCancel(shouldContinue) || !shouldContinue) {
77
+ cancel(chalk.yellow("Agent mode cancelled"));
78
+ process.exit(0);
79
+ }
80
+
81
+ const conversation = await initConversation(user.id, conversationId);
82
+ await agentLoop(conversation);
83
+
84
+ outro(chalk.green.bold("\n✨ Thanks for using Agent Mode!"));
85
+ } catch (error) {
86
+ const errorBox = boxen(chalk.red(`āŒ Error: ${error.message}`), {
87
+ padding: 1,
88
+ margin: 1,
89
+ borderStyle: "round",
90
+ borderColor: "red",
91
+ });
92
+ console.log(errorBox);
93
+ process.exit(1);
94
+ }
95
+ }
96
+
97
+ async function agentLoop(conversation) {
98
+ const helpBox = boxen(
99
+ `${chalk.cyan.bold("What can the agent do?")}\n\n` +
100
+ `${chalk.gray("• Generate complete applications from descriptions")}\n` +
101
+ `${chalk.gray("• Create all necessary files and folders")}\n` +
102
+ `${chalk.gray("• Include setup instructions and commands")}\n` +
103
+ `${chalk.gray("• Generate production-ready code")}\n\n` +
104
+ `${chalk.yellow.bold("Examples:")}\n` +
105
+ `${chalk.white('• "Build a todo app with React and Tailwind"')}\n` +
106
+ `${chalk.white('• "Create a REST API with Express and MongoDB"')}\n` +
107
+ `${chalk.white('• "Make a weather app using OpenWeatherMap API"')}\n\n` +
108
+ `${chalk.gray('Type "exit" to end the session')}`,
109
+ {
110
+ padding: 1,
111
+ margin: { bottom: 1 },
112
+ borderStyle: "round",
113
+ borderColor: "cyan",
114
+ title: "šŸ’” Agent Instructions",
115
+ },
116
+ );
117
+
118
+ console.log(helpBox);
119
+
120
+ while (true) {
121
+ const userInput = await text({
122
+ message: chalk.magenta("šŸ¤– What would you like to build?"),
123
+ placeholder: "Describe your application...",
124
+ validate(value) {
125
+ if (!value || value.trim().length === 0) {
126
+ return "Description cannot be empty";
127
+ }
128
+ if (value.trim().length < 10) {
129
+ return "Please provide more details (at least 10 characters)";
130
+ }
131
+ },
132
+ });
133
+
134
+ if (isCancel(userInput)) {
135
+ console.log(chalk.yellow("\nšŸ‘‹ Agent session cancelled\n"));
136
+ process.exit(0);
137
+ }
138
+
139
+ if (userInput.toLowerCase() === "exit") {
140
+ console.log(chalk.yellow("\nšŸ‘‹ Agent session ended\n"));
141
+ break;
142
+ }
143
+
144
+ const userBox = boxen(chalk.white(userInput), {
145
+ padding: 1,
146
+ margin: { top: 1, bottom: 1 },
147
+ borderStyle: "round",
148
+ borderColor: "blue",
149
+ title: "šŸ‘¤ Your Request",
150
+ titleAlignment: "left",
151
+ });
152
+ console.log(userBox);
153
+
154
+ await saveMessage(conversation.id, "user", userInput);
155
+
156
+ try {
157
+ const result = await generateApplication(
158
+ userInput,
159
+ aiService,
160
+ process.cwd(),
161
+ );
162
+
163
+ if (result && result.success) {
164
+ const responseMessage =
165
+ `Generated application: ${result.folderName}\n` +
166
+ `Files created: ${result.files.length}\n` +
167
+ `Location: ${result.appDir}\n\n` +
168
+ `Setup commands:\n${result.commands.join("\n")}`;
169
+
170
+ await saveMessage(conversation.id, "assistant", responseMessage);
171
+
172
+ const continuePrompt = await confirm({
173
+ message: chalk.cyan(
174
+ "Would you like to generate another application?",
175
+ ),
176
+ initialValue: false,
177
+ });
178
+ if (isCancel(continuePrompt) || !continuePrompt) {
179
+ console.log(
180
+ chalk.yellow("\nšŸ‘‹ Great! Check your new application.\n"),
181
+ );
182
+ break;
183
+ }
184
+ } else {
185
+ throw new Error("Generation returned no result");
186
+ }
187
+ } catch (error) {
188
+ console.log(chalk.red(`\nāŒ Error: ${error.message}\n`));
189
+
190
+ await saveMessage(
191
+ conversation.id,
192
+ "assistant",
193
+ `Error: ${error.message}`,
194
+ );
195
+
196
+ const retry = await confirm({
197
+ message: chalk.cyan("Would you like to try again?"),
198
+ initialValue: true,
199
+ });
200
+
201
+ if (isCancel(retry) || !retry) {
202
+ break;
203
+ }
204
+ }
205
+ }
206
+ }