prituscode 1.0.0 → 2.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/.env.example +2 -0
- package/package.json +16 -10
- package/prituscode.js +639 -305
- package/README.md +0 -79
package/.env.example
ADDED
package/package.json
CHANGED
|
@@ -1,17 +1,23 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "prituscode",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"description": "PRITUS CODE - Production-ready terminal AI coding agent CLI",
|
|
5
5
|
"main": "prituscode.js",
|
|
6
6
|
"bin": {
|
|
7
|
-
"prituscode": "
|
|
8
|
-
},
|
|
9
|
-
"scripts": {
|
|
10
|
-
"start": "node ./prituscode.js"
|
|
7
|
+
"prituscode": "prituscode.js"
|
|
11
8
|
},
|
|
9
|
+
"keywords": [
|
|
10
|
+
"pritus",
|
|
11
|
+
"prituscode",
|
|
12
|
+
"ai",
|
|
13
|
+
"agent",
|
|
14
|
+
"cli",
|
|
15
|
+
"coding",
|
|
16
|
+
"terminal"
|
|
17
|
+
],
|
|
18
|
+
"author": "Pritus AI",
|
|
19
|
+
"license": "MIT",
|
|
12
20
|
"engines": {
|
|
13
21
|
"node": ">=18.0.0"
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
"license": "ISC"
|
|
17
|
-
}
|
|
22
|
+
}
|
|
23
|
+
}
|
package/prituscode.js
CHANGED
|
@@ -1,359 +1,693 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
const
|
|
5
|
-
const
|
|
6
|
-
const
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
for (let i = 0; i < args.length; i++) {
|
|
29
|
-
if (args[i] === '--endpoint' && args[i + 1]) {
|
|
30
|
-
config.endpoint = args[++i];
|
|
31
|
-
} else if (args[i] === '--model' && args[i + 1]) {
|
|
32
|
-
config.tier = args[++i];
|
|
33
|
-
} else if (!args[i].startsWith('--')) {
|
|
34
|
-
config.oneShotPrompt = args.slice(i).join(' ');
|
|
35
|
-
break;
|
|
3
|
+
// --- IMPORTS ---
|
|
4
|
+
const readline = require('readline')
|
|
5
|
+
const { URL } = require('url')
|
|
6
|
+
const path = require('path')
|
|
7
|
+
const os = require('os')
|
|
8
|
+
const fs = require('fs')
|
|
9
|
+
|
|
10
|
+
// --- ENVIRONMENT & CONFIGURATION ---
|
|
11
|
+
function loadEnv() {
|
|
12
|
+
const envPath = path.join(process.cwd(), '.env')
|
|
13
|
+
if (!fs.existsSync(envPath)) return
|
|
14
|
+
try {
|
|
15
|
+
const content = fs.readFileSync(envPath, 'utf8')
|
|
16
|
+
const lines = content.split('\n')
|
|
17
|
+
for (let i = 0; i < lines.length; i++) {
|
|
18
|
+
const line = lines[i].trim()
|
|
19
|
+
if (!line || line.startsWith('#')) continue
|
|
20
|
+
const eqIdx = line.indexOf('=')
|
|
21
|
+
if (eqIdx > 0) {
|
|
22
|
+
const key = line.slice(0, eqIdx).trim()
|
|
23
|
+
const val = line.slice(eqIdx + 1).trim()
|
|
24
|
+
if (!process.env[key]) {
|
|
25
|
+
process.env[key] = val
|
|
26
|
+
}
|
|
27
|
+
}
|
|
36
28
|
}
|
|
29
|
+
} catch (err) {
|
|
30
|
+
// Ignore env load errors silently
|
|
31
|
+
}
|
|
37
32
|
}
|
|
38
33
|
|
|
39
|
-
|
|
40
|
-
const AGENT_SYSTEM = `
|
|
41
|
-
You are PRITUS CODE, an elite terminal-based AI coding agent.
|
|
42
|
-
When generating or modifying code, you must ACT as an agent. Use the exact format below:
|
|
34
|
+
loadEnv()
|
|
43
35
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
DONE: <short summary of what was done>
|
|
36
|
+
const VERSION = '1.0.0'
|
|
37
|
+
const DEFAULT_API_URL = process.env.PRITUS_API_URL || 'https://pritusai.netlify.app'
|
|
38
|
+
const DEFAULT_MODEL = process.env.PRITUS_MODEL || 'pro'
|
|
48
39
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
40
|
+
const MODELS = {
|
|
41
|
+
1: { id: 'flash', label: 'Flash', desc: 'Fast & lightweight' },
|
|
42
|
+
2: { id: 'pro', label: 'Pro', desc: 'Balanced — general use' },
|
|
43
|
+
3: { id: 'thinking', label: 'Thinking', desc: 'Deep reasoning' },
|
|
44
|
+
4: { id: 'ultra', label: 'Ultra Code', desc: 'Elite code generation' }
|
|
45
|
+
}
|
|
52
46
|
|
|
53
|
-
|
|
54
|
-
|
|
47
|
+
const AGENT_SYSTEM = `You are Pritus Code, an AI coding agent in a terminal. You CREATE and MODIFY real files.
|
|
48
|
+
When asked to build something, respond in EXACT format:
|
|
49
|
+
THINKING: <one sentence>
|
|
50
|
+
CREATE_FILE: <filename>
|
|
51
|
+
\`\`\`<language>
|
|
52
|
+
<full file content>
|
|
53
|
+
\`\`\`
|
|
54
|
+
`
|
|
55
|
+
|
|
56
|
+
// --- ANSI & FORMATTING HELPERS ---
|
|
57
|
+
function stripAnsi(str) {
|
|
58
|
+
return str.replace(/\x1B\[[0-9;]{0,}[A-Za-z]/g, '')
|
|
59
|
+
}
|
|
55
60
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
prompt: `${c.magenta}${c.bold}> ${c.rst}`
|
|
60
|
-
});
|
|
61
|
+
function bold(str) {
|
|
62
|
+
return '\x1b[1m' + str + '\x1b[22m'
|
|
63
|
+
}
|
|
61
64
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
}
|
|
65
|
+
function dim(str) {
|
|
66
|
+
return '\x1b[2m' + str + '\x1b[22m'
|
|
67
|
+
}
|
|
65
68
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
process.stdout.write('\x1B[2J\x1B[0f');
|
|
69
|
+
function cyan(str) {
|
|
70
|
+
return '\x1b[36m' + str + '\x1b[39m'
|
|
69
71
|
}
|
|
70
72
|
|
|
71
|
-
function
|
|
72
|
-
|
|
73
|
-
const d1 = '\x1b[38;5;33m';
|
|
74
|
-
const d2 = '\x1b[38;5;39m';
|
|
75
|
-
const d3 = '\x1b[38;5;135m';
|
|
76
|
-
const d4 = '\x1b[38;5;165m';
|
|
77
|
-
const d5 = '\x1b[38;5;199m';
|
|
78
|
-
|
|
79
|
-
console.log(`
|
|
80
|
-
${d1} /\\ ${c.bold}██████╗ ██████╗ ██╗████████╗██╗ ██╗███████╗${c.rst}
|
|
81
|
-
${d2} / \\ ${c.bold}██╔══██╗██╔══██╗██║╚══██╔══╝██║ ██║██╔════╝${c.rst}
|
|
82
|
-
${d3} /____\\ ${c.bold}██████╔╝██████╔╝██║ ██║ ██║ ██║███████╗${c.rst}
|
|
83
|
-
${d4} \\ / ${c.bold}██╔═══╝ ██╔══██╗██║ ██║ ██║ ██║╚════██║${c.rst}
|
|
84
|
-
${d5} \\ / ${c.bold}██║ ██║ ██║██║ ██║ ╚██████╔╝███████║${c.rst}
|
|
85
|
-
${c.magenta} \\/ ${c.bold}╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝ ╚══════╝${c.rst}
|
|
86
|
-
${c.dim}v1.0.0${c.rst}
|
|
87
|
-
`);
|
|
73
|
+
function green(str) {
|
|
74
|
+
return '\x1b[32m' + str + '\x1b[39m'
|
|
88
75
|
}
|
|
89
76
|
|
|
90
|
-
function
|
|
91
|
-
|
|
92
|
-
const boxWidth = Math.max(60, cwd.length + 20);
|
|
93
|
-
const line = '─'.repeat(boxWidth - 2);
|
|
94
|
-
console.log(`${c.magenta}┌${line}┐${c.rst}`);
|
|
95
|
-
console.log(`${c.magenta}│${c.rst} ${c.bold}Welcome to PRITUS CODE${c.rst}`.padEnd(boxWidth + c.magenta.length + c.rst.length + c.bold.length + c.rst.length - 1) + `${c.magenta}│${c.rst}`);
|
|
96
|
-
console.log(`${c.magenta}│${c.rst} ${c.dim}Type /help for commands, @filename to attach files${c.rst}`.padEnd(boxWidth + c.magenta.length + c.rst.length + c.dim.length + c.rst.length - 1) + `${c.magenta}│${c.rst}`);
|
|
97
|
-
console.log(`${c.magenta}│${c.rst} ${c.cyan}Workspace: ${cwd}${c.rst}`.padEnd(boxWidth + c.magenta.length + c.rst.length + c.cyan.length + c.rst.length - 1) + `${c.magenta}│${c.rst}`);
|
|
98
|
-
console.log(`${c.magenta}└${line}┘${c.rst}\n`);
|
|
99
|
-
|
|
100
|
-
console.log(`${c.bold}Tips:${c.rst}`);
|
|
101
|
-
console.log(` 1. Use @file to include file context`);
|
|
102
|
-
console.log(` 2. Type /model to switch intelligence tiers`);
|
|
103
|
-
console.log(` 3. Type /init to set up project instructions`);
|
|
104
|
-
console.log(` 4. Let the agent build files for you ${c.green}✓${c.rst}\n`);
|
|
77
|
+
function magenta(str) {
|
|
78
|
+
return '\x1b[35m' + str + '\x1b[39m'
|
|
105
79
|
}
|
|
106
80
|
|
|
107
|
-
function
|
|
108
|
-
|
|
109
|
-
const bar = `${c.bgMagenta}${c.white} ${cwd} ${c.rst} ${c.dim}model:${c.rst} ${config.tier} ${c.dim}| /help for menu${c.rst}`;
|
|
110
|
-
console.log(`\n${bar}`);
|
|
81
|
+
function brightMagenta(str) {
|
|
82
|
+
return '\x1b[95m' + str + '\x1b[39m'
|
|
111
83
|
}
|
|
112
84
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
let i = 0;
|
|
116
|
-
const interval = setInterval(() => {
|
|
117
|
-
process.stdout.write(`\r${c.magenta}${frames[i]}${c.rst} ${c.dim}${text}...${c.rst}`);
|
|
118
|
-
i = (i + 1) % frames.length;
|
|
119
|
-
}, 80);
|
|
120
|
-
return () => {
|
|
121
|
-
clearInterval(interval);
|
|
122
|
-
process.stdout.write('\r\x1b[K'); // clear line
|
|
123
|
-
};
|
|
85
|
+
function ansi256(code, str) {
|
|
86
|
+
return '\x1b[38;5;' + code + 'm' + str + '\x1b[0m'
|
|
124
87
|
}
|
|
125
88
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
console.log();
|
|
89
|
+
function formatPath(p) {
|
|
90
|
+
const home = os.homedir()
|
|
91
|
+
if (p.startsWith(home)) {
|
|
92
|
+
return '~' + p.slice(home.length)
|
|
93
|
+
}
|
|
94
|
+
return p
|
|
133
95
|
}
|
|
134
96
|
|
|
135
|
-
// ---
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
case '4': config.tier = 'code'; break;
|
|
148
|
-
case '2':
|
|
149
|
-
default: config.tier = 'pro'; break;
|
|
150
|
-
}
|
|
151
|
-
console.log(`${c.green}✓ Switched to ${config.tier} tier${c.rst}\n`);
|
|
97
|
+
// --- LOGO & ASCII ART GENERATORS ---
|
|
98
|
+
function getDiamondLogo() {
|
|
99
|
+
const lines = [
|
|
100
|
+
ansi256(39, '██'),
|
|
101
|
+
' ' + ansi256(75, '██'),
|
|
102
|
+
' ' + ansi256(99, '██'),
|
|
103
|
+
' ' + ansi256(141, '██'),
|
|
104
|
+
' ' + ansi256(177, '██'),
|
|
105
|
+
ansi256(207, '██'),
|
|
106
|
+
ansi256(207, '████████')
|
|
107
|
+
]
|
|
108
|
+
return lines
|
|
152
109
|
}
|
|
153
110
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
111
|
+
const LETTERS = {
|
|
112
|
+
P: [
|
|
113
|
+
'██████╗ ',
|
|
114
|
+
'██╔══██╗',
|
|
115
|
+
'██████╔╝',
|
|
116
|
+
'██╔═══╝ ',
|
|
117
|
+
'██║ ',
|
|
118
|
+
'╚═╝ '
|
|
119
|
+
],
|
|
120
|
+
R: [
|
|
121
|
+
'██████╗ ',
|
|
122
|
+
'██╔══██╗',
|
|
123
|
+
'██████╔╝',
|
|
124
|
+
'██╔██╗ ',
|
|
125
|
+
'██║╚██╗ ',
|
|
126
|
+
'╚═╝ ╚═╝ '
|
|
127
|
+
],
|
|
128
|
+
I: [
|
|
129
|
+
'██╗',
|
|
130
|
+
'██║',
|
|
131
|
+
'██║',
|
|
132
|
+
'██║',
|
|
133
|
+
'██║',
|
|
134
|
+
'╚═╝'
|
|
135
|
+
],
|
|
136
|
+
T: [
|
|
137
|
+
'████████╗',
|
|
138
|
+
'╚══██╔══╝',
|
|
139
|
+
' ██║ ',
|
|
140
|
+
' ██║ ',
|
|
141
|
+
' ██║ ',
|
|
142
|
+
' ╚═╝ '
|
|
143
|
+
],
|
|
144
|
+
U: [
|
|
145
|
+
'██╗ ██╗',
|
|
146
|
+
'██║ ██║',
|
|
147
|
+
'██║ ██║',
|
|
148
|
+
'██║ ██║',
|
|
149
|
+
'╚██████╔╝',
|
|
150
|
+
' ╚═════╝ '
|
|
151
|
+
],
|
|
152
|
+
S: [
|
|
153
|
+
'███████╗',
|
|
154
|
+
'██╔════╝',
|
|
155
|
+
'███████╗',
|
|
156
|
+
'╚════██║',
|
|
157
|
+
'███████║',
|
|
158
|
+
'╚══════╝'
|
|
159
|
+
],
|
|
160
|
+
C: [
|
|
161
|
+
'███████╗',
|
|
162
|
+
'██╔════╝',
|
|
163
|
+
'██║ ',
|
|
164
|
+
'██║ ',
|
|
165
|
+
'╚██████╗',
|
|
166
|
+
' ╚═════╝'
|
|
167
|
+
],
|
|
168
|
+
O: [
|
|
169
|
+
' █████╗ ',
|
|
170
|
+
'██╔══██╗',
|
|
171
|
+
'██║ ██║',
|
|
172
|
+
'██║ ██║',
|
|
173
|
+
'╚██████╔╝',
|
|
174
|
+
' ╚═════╝ '
|
|
175
|
+
],
|
|
176
|
+
D: [
|
|
177
|
+
'██████╗ ',
|
|
178
|
+
'██╔══██╗',
|
|
179
|
+
'██║ ██║',
|
|
180
|
+
'██║ ██║',
|
|
181
|
+
'╚██████╗',
|
|
182
|
+
' ╚═════╝ '
|
|
183
|
+
],
|
|
184
|
+
E: [
|
|
185
|
+
'███████╗',
|
|
186
|
+
'██╔════╝',
|
|
187
|
+
'███████╗',
|
|
188
|
+
'██╔════╝',
|
|
189
|
+
'███████╝',
|
|
190
|
+
' '
|
|
191
|
+
]
|
|
192
|
+
}
|
|
159
193
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
194
|
+
function getBigBanner() {
|
|
195
|
+
const rows = []
|
|
196
|
+
for (let r = 0; r < 6; r++) {
|
|
197
|
+
const pritusLine = LETTERS.P[r] + ' ' + LETTERS.R[r] + ' ' + LETTERS.I[r] + ' ' + LETTERS.T[r] + ' ' + LETTERS.U[r] + ' ' + LETTERS.S[r]
|
|
198
|
+
const codeLine = LETTERS.C[r] + ' ' + LETTERS.O[r] + ' ' + LETTERS.D[r] + ' ' + LETTERS.E[r]
|
|
199
|
+
rows.push(pritusLine + ' ' + codeLine)
|
|
200
|
+
}
|
|
201
|
+
return rows
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
function renderHeader() {
|
|
205
|
+
const diamond = getDiamondLogo()
|
|
206
|
+
const banner = getBigBanner()
|
|
207
|
+
|
|
208
|
+
console.log('')
|
|
209
|
+
for (let i = 0; i < 7; i++) {
|
|
210
|
+
const dia = diamond[i]
|
|
211
|
+
const ban = i < 6 ? cyan(banner[i]) : ''
|
|
212
|
+
console.log(dia + ' ' + ban)
|
|
213
|
+
}
|
|
214
|
+
console.log(brightMagenta(bold('PRITUS CODE v' + VERSION)))
|
|
215
|
+
console.log('')
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
function renderWelcomeBox(cwd) {
|
|
219
|
+
const displayCwd = formatPath(cwd)
|
|
220
|
+
const line1 = 'Welcome to Pritus Code!'
|
|
221
|
+
const line2 = '/help for help, /status for your current setup'
|
|
222
|
+
const line3 = 'cwd: ' + displayCwd
|
|
223
|
+
|
|
224
|
+
let innerWidth = line1.length
|
|
225
|
+
if (line2.length > innerWidth) innerWidth = line2.length
|
|
226
|
+
if (line3.length > innerWidth) innerWidth = line3.length
|
|
227
|
+
innerWidth += 4
|
|
228
|
+
|
|
229
|
+
const topBorder = '┌' + '─'.repeat(innerWidth) + '┐'
|
|
230
|
+
const bottomBorder = '└' + '─'.repeat(innerWidth) + '┘'
|
|
231
|
+
|
|
232
|
+
console.log(cyan(topBorder))
|
|
233
|
+
|
|
234
|
+
const pad1 = ' '.repeat(innerWidth - line1.length - 2)
|
|
235
|
+
console.log(cyan('│ ') + bold(line1) + pad1 + cyan(' │'))
|
|
236
|
+
|
|
237
|
+
const pad2 = ' '.repeat(innerWidth - line2.length - 2)
|
|
238
|
+
console.log(cyan('│ ') + dim(line2) + pad2 + cyan(' │'))
|
|
239
|
+
|
|
240
|
+
const pad3 = ' '.repeat(innerWidth - line3.length - 2)
|
|
241
|
+
console.log(cyan('│ ') + dim(line3) + pad3 + cyan(' │'))
|
|
242
|
+
|
|
243
|
+
console.log(cyan(bottomBorder))
|
|
244
|
+
console.log('')
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
function renderTips() {
|
|
248
|
+
console.log(bold('Tips for getting started:'))
|
|
249
|
+
console.log('1. Ask Pritus to build something — it will create actual files in your project')
|
|
250
|
+
console.log('2. Use @filename to include a file contents in your message')
|
|
251
|
+
console.log('3. Be as specific as you would with another engineer for the best results')
|
|
252
|
+
console.log(green('✓') + ' Run /init to create a PRITUS.md with project instructions')
|
|
253
|
+
console.log('')
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
function renderStatusBar(currentModelId, cwd) {
|
|
257
|
+
const displayCwd = formatPath(cwd)
|
|
258
|
+
const selectedObj = getModelInfo(currentModelId)
|
|
259
|
+
const barText = 'workspace (' + displayCwd + ') /model ' + selectedObj.id + ' ? for shortcuts'
|
|
260
|
+
console.log(dim(barText))
|
|
261
|
+
console.log('')
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
function getModelInfo(keyOrId) {
|
|
265
|
+
const str = String(keyOrId).toLowerCase()
|
|
266
|
+
for (const k in MODELS) {
|
|
267
|
+
if (String(k) === str || MODELS[k].id === str) {
|
|
268
|
+
return MODELS[k]
|
|
172
269
|
}
|
|
173
|
-
|
|
270
|
+
}
|
|
271
|
+
return MODELS[2]
|
|
174
272
|
}
|
|
175
273
|
|
|
176
|
-
// ---
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
const
|
|
181
|
-
const
|
|
274
|
+
// --- MODEL SELECTOR ---
|
|
275
|
+
function promptModelSelection(currentModelId, callback) {
|
|
276
|
+
console.log('Select a model:')
|
|
277
|
+
for (const k in MODELS) {
|
|
278
|
+
const m = MODELS[k]
|
|
279
|
+
const isSelected = m.id === currentModelId
|
|
280
|
+
const pointer = isSelected ? '▸ ' : ' '
|
|
281
|
+
const num = k + ' '
|
|
282
|
+
console.log(pointer + num + bold(m.label) + ' — ' + m.desc)
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
const defaultModelObj = getModelInfo(currentModelId)
|
|
286
|
+
process.stdout.write('Press 1-4, or Enter for ' + defaultModelObj.id + ': ')
|
|
287
|
+
|
|
288
|
+
if (process.stdin.isTTY) {
|
|
289
|
+
process.stdin.setRawMode(true)
|
|
290
|
+
process.stdin.resume()
|
|
291
|
+
process.stdin.once('data', (data) => {
|
|
292
|
+
process.stdin.setRawMode(false)
|
|
293
|
+
process.stdin.pause()
|
|
294
|
+
const char = data.toString('utf8').trim()
|
|
295
|
+
console.log(char)
|
|
296
|
+
|
|
297
|
+
let choiceObj = defaultModelObj
|
|
298
|
+
if (MODELS[char]) {
|
|
299
|
+
choiceObj = MODELS[char]
|
|
300
|
+
}
|
|
301
|
+
console.log(green('✓') + ' Switched to ' + choiceObj.label)
|
|
302
|
+
console.log('')
|
|
303
|
+
callback(choiceObj.id)
|
|
304
|
+
})
|
|
305
|
+
} else {
|
|
306
|
+
const rlTemp = readline.createInterface({
|
|
307
|
+
input: process.stdin,
|
|
308
|
+
output: process.stdout
|
|
309
|
+
})
|
|
310
|
+
rlTemp.question('', (ans) => {
|
|
311
|
+
rlTemp.close()
|
|
312
|
+
const trimmed = ans.trim()
|
|
313
|
+
let choiceObj = defaultModelObj
|
|
314
|
+
if (MODELS[trimmed]) {
|
|
315
|
+
choiceObj = MODELS[trimmed]
|
|
316
|
+
}
|
|
317
|
+
console.log(green('✓') + ' Switched to ' + choiceObj.label)
|
|
318
|
+
console.log('')
|
|
319
|
+
callback(choiceObj.id)
|
|
320
|
+
})
|
|
321
|
+
}
|
|
322
|
+
}
|
|
182
323
|
|
|
183
|
-
|
|
324
|
+
// --- FILE PARSER & AGENT OPERATIONS ---
|
|
325
|
+
function processFileOperations(aiResponse) {
|
|
326
|
+
let modifiedAny = false
|
|
327
|
+
const createPattern = /CREATE_FILE:\s{0,}([^\n]+)\n```[a-z]{0,}\n([\s\S]+?)```/gi
|
|
328
|
+
const modifyPattern = /MODIFY_FILE:\s{0,}([^\n]+)\n```[a-z]{0,}\n([\s\S]+?)```/gi
|
|
184
329
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
330
|
+
let match
|
|
331
|
+
while ((match = createPattern.exec(aiResponse)) !== null) {
|
|
332
|
+
const fileName = match[1].trim()
|
|
333
|
+
const content = match[2]
|
|
334
|
+
try {
|
|
335
|
+
const targetPath = path.resolve(process.cwd(), fileName)
|
|
336
|
+
fs.mkdirSync(path.dirname(targetPath), { recursive: true })
|
|
337
|
+
fs.writeFileSync(targetPath, content, 'utf8')
|
|
338
|
+
const bytes = Buffer.byteLength(content, 'utf8')
|
|
339
|
+
console.log(green('✓ Created ') + fileName + ' (' + bytes + ' bytes)')
|
|
340
|
+
modifiedAny = true
|
|
341
|
+
} catch (err) {
|
|
342
|
+
console.log('\x1b[31mError creating file ' + fileName + ': ' + err.message + '\x1b[39m')
|
|
188
343
|
}
|
|
344
|
+
}
|
|
189
345
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
fs.writeFileSync(fullPath, content);
|
|
203
|
-
console.log(`${c.cyan}└─ ${c.green}✓ Created successfully${c.rst}`);
|
|
204
|
-
fileCount++;
|
|
205
|
-
} catch (err) {
|
|
206
|
-
console.log(`${c.cyan}└─ ${c.red}✗ Failed: ${err.message}${c.rst}`);
|
|
207
|
-
}
|
|
346
|
+
while ((match = modifyPattern.exec(aiResponse)) !== null) {
|
|
347
|
+
const fileName = match[1].trim()
|
|
348
|
+
const content = match[2]
|
|
349
|
+
try {
|
|
350
|
+
const targetPath = path.resolve(process.cwd(), fileName)
|
|
351
|
+
fs.mkdirSync(path.dirname(targetPath), { recursive: true })
|
|
352
|
+
fs.writeFileSync(targetPath, content, 'utf8')
|
|
353
|
+
const bytes = Buffer.byteLength(content, 'utf8')
|
|
354
|
+
console.log(green('✓ Modified ') + fileName + ' (' + bytes + ' bytes)')
|
|
355
|
+
modifiedAny = true
|
|
356
|
+
} catch (err) {
|
|
357
|
+
console.log('\x1b[31mError modifying file ' + fileName + ': ' + err.message + '\x1b[39m')
|
|
208
358
|
}
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
return modifiedAny
|
|
362
|
+
}
|
|
209
363
|
|
|
210
|
-
|
|
211
|
-
|
|
364
|
+
function expandFileAttachments(text) {
|
|
365
|
+
const atPattern = /@([^\s]+)/g
|
|
366
|
+
let match
|
|
367
|
+
let expanded = text
|
|
368
|
+
const attachedFiles = []
|
|
369
|
+
|
|
370
|
+
while ((match = atPattern.exec(text)) !== null) {
|
|
371
|
+
const fileRef = match[1]
|
|
372
|
+
const filePath = path.resolve(process.cwd(), fileRef)
|
|
373
|
+
if (fs.existsSync(filePath) && fs.statSync(filePath).isFile()) {
|
|
374
|
+
try {
|
|
375
|
+
const fileContent = fs.readFileSync(filePath, 'utf8')
|
|
376
|
+
attachedFiles.push({ ref: fileRef, content: fileContent })
|
|
377
|
+
} catch (e) {
|
|
378
|
+
// file unreadable
|
|
379
|
+
}
|
|
212
380
|
}
|
|
381
|
+
}
|
|
213
382
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
383
|
+
if (attachedFiles.length > 0) {
|
|
384
|
+
let header = ''
|
|
385
|
+
for (let i = 0; i < attachedFiles.length; i++) {
|
|
386
|
+
header += '[Attached file: ' + attachedFiles[i].ref + ']\n' + attachedFiles[i].content + '\n[End attached file]\n\n'
|
|
217
387
|
}
|
|
218
|
-
|
|
388
|
+
expanded = header + text
|
|
389
|
+
}
|
|
219
390
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
const finalPrompt = processAtFiles(prompt);
|
|
223
|
-
messages.push({ role: 'user', content: finalPrompt });
|
|
391
|
+
return expanded
|
|
392
|
+
}
|
|
224
393
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
394
|
+
// --- HTTP API CLIENT ---
|
|
395
|
+
function sendChatRequest(apiUrl, modelId, userPrompt, messagesHistory, callback) {
|
|
396
|
+
const expandedPrompt = expandFileAttachments(userPrompt)
|
|
397
|
+
|
|
398
|
+
let targetUrl = apiUrl
|
|
399
|
+
if (!targetUrl.endsWith('/api/pritus/chat')) {
|
|
400
|
+
if (targetUrl.endsWith('/')) {
|
|
401
|
+
targetUrl += 'api/pritus/chat'
|
|
402
|
+
} else {
|
|
403
|
+
targetUrl += '/api/pritus/chat'
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
let parsedUrl
|
|
408
|
+
try {
|
|
409
|
+
parsedUrl = new URL(targetUrl)
|
|
410
|
+
} catch (e) {
|
|
411
|
+
console.log('\x1b[31mInvalid API URL: ' + targetUrl + '\x1b[39m')
|
|
412
|
+
return callback(new Error('Invalid URL'))
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
const httpModule = parsedUrl.protocol === 'https:' ? require('https') : require('http')
|
|
416
|
+
const payload = JSON.stringify({
|
|
417
|
+
prompt: expandedPrompt,
|
|
418
|
+
model: modelId,
|
|
419
|
+
system: AGENT_SYSTEM,
|
|
420
|
+
messages: messagesHistory
|
|
421
|
+
})
|
|
422
|
+
|
|
423
|
+
const reqOpts = {
|
|
424
|
+
hostname: parsedUrl.hostname,
|
|
425
|
+
port: parsedUrl.port || (parsedUrl.protocol === 'https:' ? 443 : 80),
|
|
426
|
+
path: parsedUrl.pathname + parsedUrl.search,
|
|
427
|
+
method: 'POST',
|
|
428
|
+
headers: {
|
|
429
|
+
'Content-Type': 'application/json',
|
|
430
|
+
'Content-Length': Buffer.byteLength(payload)
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
const req = httpModule.request(reqOpts, (res) => {
|
|
435
|
+
let body = ''
|
|
436
|
+
res.on('data', (chunk) => {
|
|
437
|
+
body += chunk.toString('utf8')
|
|
438
|
+
})
|
|
439
|
+
res.on('end', () => {
|
|
440
|
+
if (res.statusCode >= 200 && res.statusCode < 300) {
|
|
441
|
+
let textResult = body
|
|
442
|
+
try {
|
|
443
|
+
const parsed = JSON.parse(body)
|
|
444
|
+
if (parsed.response) textResult = parsed.response
|
|
445
|
+
else if (parsed.message) textResult = parsed.message
|
|
446
|
+
else if (parsed.content) textResult = parsed.content
|
|
447
|
+
else if (parsed.choices && parsed.choices[0] && parsed.choices[0].message) {
|
|
448
|
+
textResult = parsed.choices[0].message.content
|
|
449
|
+
}
|
|
450
|
+
} catch (e) {
|
|
451
|
+
// Response is raw text
|
|
242
452
|
}
|
|
453
|
+
callback(null, textResult)
|
|
454
|
+
} else {
|
|
455
|
+
callback(new Error('API returned HTTP status ' + res.statusCode + ': ' + body))
|
|
456
|
+
}
|
|
457
|
+
})
|
|
458
|
+
})
|
|
459
|
+
|
|
460
|
+
req.on('error', (err) => {
|
|
461
|
+
callback(err)
|
|
462
|
+
})
|
|
463
|
+
|
|
464
|
+
req.write(payload)
|
|
465
|
+
req.end()
|
|
466
|
+
}
|
|
243
467
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
468
|
+
// --- SLASH COMMANDS HANDLER ---
|
|
469
|
+
function handleSlashCommand(input, state, rl) {
|
|
470
|
+
const parts = input.trim().split(/\s{1,}/)
|
|
471
|
+
const cmd = parts[0].toLowerCase()
|
|
472
|
+
const arg = parts.slice(1).join(' ')
|
|
473
|
+
|
|
474
|
+
switch (cmd) {
|
|
475
|
+
case '/help':
|
|
476
|
+
case '?':
|
|
477
|
+
console.log('')
|
|
478
|
+
console.log(bold('PRITUS CODE Commands & Shortcuts:'))
|
|
479
|
+
console.log(' /help, ? Show this help message')
|
|
480
|
+
console.log(' /status Show current configuration')
|
|
481
|
+
console.log(' /init Create PRITUS.md with project rules')
|
|
482
|
+
console.log(' /model [1-4] Change AI model (1: Flash, 2: Pro, 3: Thinking, 4: Ultra)')
|
|
483
|
+
console.log(' /clear Clear terminal screen')
|
|
484
|
+
console.log(' /exit, /quit Exit PRITUS CODE')
|
|
485
|
+
console.log(' @filename Include file contents in your prompt')
|
|
486
|
+
console.log('')
|
|
487
|
+
rl.prompt()
|
|
488
|
+
return true
|
|
489
|
+
|
|
490
|
+
case '/status':
|
|
491
|
+
console.log('')
|
|
492
|
+
console.log(bold('Current Setup:'))
|
|
493
|
+
console.log(' Version: ' + VERSION)
|
|
494
|
+
console.log(' Model: ' + getModelInfo(state.currentModel).label + ' (' + state.currentModel + ')')
|
|
495
|
+
console.log(' API URL: ' + state.apiUrl)
|
|
496
|
+
console.log(' CWD: ' + process.cwd())
|
|
497
|
+
console.log('')
|
|
498
|
+
rl.prompt()
|
|
499
|
+
return true
|
|
500
|
+
|
|
501
|
+
case '/init':
|
|
502
|
+
{
|
|
503
|
+
const docPath = path.join(process.cwd(), 'PRITUS.md')
|
|
504
|
+
const docContent = `# PRITUS CODE Project Instructions
|
|
505
|
+
|
|
506
|
+
## Overview
|
|
507
|
+
Describe your project and architectural guidelines here for Pritus Code.
|
|
508
|
+
|
|
509
|
+
## Guidelines
|
|
510
|
+
- Write clean, modular, and maintainable code.
|
|
511
|
+
- Always implement proper error handling.
|
|
512
|
+
`
|
|
513
|
+
try {
|
|
514
|
+
fs.writeFileSync(docPath, docContent, 'utf8')
|
|
515
|
+
console.log(green('✓ Created PRITUS.md with project instructions'))
|
|
516
|
+
} catch (err) {
|
|
517
|
+
console.log('\x1b[31mError creating PRITUS.md: ' + err.message + '\x1b[39m')
|
|
251
518
|
}
|
|
519
|
+
console.log('')
|
|
520
|
+
rl.prompt()
|
|
521
|
+
}
|
|
522
|
+
return true
|
|
523
|
+
|
|
524
|
+
case '/model':
|
|
525
|
+
if (arg) {
|
|
526
|
+
const info = getModelInfo(arg)
|
|
527
|
+
state.currentModel = info.id
|
|
528
|
+
console.log(green('✓ Switched to ') + info.label)
|
|
529
|
+
console.log('')
|
|
530
|
+
rl.prompt()
|
|
531
|
+
} else {
|
|
532
|
+
promptModelSelection(state.currentModel, (newModel) => {
|
|
533
|
+
state.currentModel = newModel
|
|
534
|
+
rl.prompt()
|
|
535
|
+
})
|
|
536
|
+
}
|
|
537
|
+
return true
|
|
538
|
+
|
|
539
|
+
case '/clear':
|
|
540
|
+
console.clear()
|
|
541
|
+
renderHeader()
|
|
542
|
+
renderStatusBar(state.currentModel, process.cwd())
|
|
543
|
+
rl.prompt()
|
|
544
|
+
return true
|
|
545
|
+
|
|
546
|
+
case '/exit':
|
|
547
|
+
case '/quit':
|
|
548
|
+
console.log(dim('Goodbye!'))
|
|
549
|
+
process.exit(0)
|
|
550
|
+
return true
|
|
551
|
+
|
|
552
|
+
default:
|
|
553
|
+
if (cmd.startsWith('/')) {
|
|
554
|
+
console.log('\x1b[31mUnknown command: ' + cmd + '. Type /help for assistance.\x1b[39m')
|
|
555
|
+
console.log('')
|
|
556
|
+
rl.prompt()
|
|
557
|
+
return true
|
|
558
|
+
}
|
|
559
|
+
return false
|
|
560
|
+
}
|
|
561
|
+
}
|
|
252
562
|
|
|
253
|
-
|
|
254
|
-
|
|
563
|
+
// --- MAIN REPL LOOP ---
|
|
564
|
+
function startRepl(state) {
|
|
565
|
+
const rl = readline.createInterface({
|
|
566
|
+
input: process.stdin,
|
|
567
|
+
output: process.stdout,
|
|
568
|
+
prompt: '> '
|
|
569
|
+
})
|
|
255
570
|
|
|
256
|
-
|
|
257
|
-
stopLoading();
|
|
258
|
-
console.log(`${c.red}Pritus AI is suffering from heavy traffic right now. (Error: ${error.message})${c.rst}`);
|
|
259
|
-
// Remove the failed message so they can retry
|
|
260
|
-
messages.pop();
|
|
261
|
-
}
|
|
262
|
-
}
|
|
571
|
+
const messagesHistory = []
|
|
263
572
|
|
|
264
|
-
|
|
265
|
-
async function handleLogin() {
|
|
266
|
-
console.log(`\n${c.bold}Google Authentication${c.rst}`);
|
|
267
|
-
const code = Math.random().toString(36).substring(2, 10).toUpperCase();
|
|
268
|
-
console.log(`${c.dim}Please go to: ${c.white}https://google.com/device${c.rst}`);
|
|
269
|
-
console.log(`${c.dim}And enter this code: ${c.magenta}${c.bold}${code}${c.rst}\n`);
|
|
270
|
-
|
|
271
|
-
const stop = await startLoading('Waiting for authorization');
|
|
272
|
-
await sleep(4000); // Simulate waiting for external auth
|
|
273
|
-
stop();
|
|
274
|
-
|
|
275
|
-
const tokenPath = path.join(os.homedir(), '.prituscode_auth');
|
|
276
|
-
fs.writeFileSync(tokenPath, `mock_token_${Date.now()}`);
|
|
277
|
-
console.log(`${c.green}✓ Successfully logged in with Google!${c.rst}\n`);
|
|
278
|
-
}
|
|
573
|
+
rl.prompt()
|
|
279
574
|
|
|
575
|
+
rl.on('line', (line) => {
|
|
576
|
+
const input = line.trim()
|
|
577
|
+
if (!input) {
|
|
578
|
+
rl.prompt()
|
|
579
|
+
return
|
|
580
|
+
}
|
|
280
581
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
if (config.oneShotPrompt) {
|
|
284
|
-
console.log(`${c.magenta}PRITUS CODE${c.rst} ${c.dim}> One-shot mode${c.rst}\n`);
|
|
285
|
-
await handleChat(config.oneShotPrompt);
|
|
286
|
-
process.exit(0);
|
|
582
|
+
if (handleSlashCommand(input, state, rl)) {
|
|
583
|
+
return
|
|
287
584
|
}
|
|
288
585
|
|
|
289
|
-
|
|
290
|
-
printLogo();
|
|
291
|
-
printWelcomeBox();
|
|
292
|
-
|
|
293
|
-
// Auto-prompt for model on first run if in interactive mode
|
|
294
|
-
await selectModel();
|
|
295
|
-
printStatusBar();
|
|
296
|
-
|
|
297
|
-
rl.prompt();
|
|
298
|
-
|
|
299
|
-
rl.on('line', async (line) => {
|
|
300
|
-
const input = line.trim();
|
|
301
|
-
if (!input) {
|
|
302
|
-
rl.prompt();
|
|
303
|
-
return;
|
|
304
|
-
}
|
|
586
|
+
process.stdout.write(dim('Thinking... \r'))
|
|
305
587
|
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
console.log(` /model Change AI tier (flash, pro, thinking, code)`);
|
|
337
|
-
console.log(` /init Create a PRITUS.md instruction file`);
|
|
338
|
-
console.log(` /clear Clear conversation history`);
|
|
339
|
-
console.log(` /status Show current agent status`);
|
|
340
|
-
console.log(` /login Authenticate with Google`);
|
|
341
|
-
console.log(` /exit Close PRITUS CODE\n`);
|
|
342
|
-
break;
|
|
343
|
-
default:
|
|
344
|
-
await handleChat(input);
|
|
345
|
-
break;
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
printStatusBar();
|
|
349
|
-
rl.prompt();
|
|
350
|
-
});
|
|
588
|
+
sendChatRequest(state.apiUrl, state.currentModel, input, messagesHistory, (err, responseText) => {
|
|
589
|
+
// Clear line
|
|
590
|
+
process.stdout.write(' \r')
|
|
591
|
+
|
|
592
|
+
if (err) {
|
|
593
|
+
console.log('\x1b[31mError: ' + err.message + '\x1b[39m')
|
|
594
|
+
console.log('')
|
|
595
|
+
rl.prompt()
|
|
596
|
+
return
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
console.log(responseText)
|
|
600
|
+
console.log('')
|
|
601
|
+
|
|
602
|
+
const opsExecuted = processFileOperations(responseText)
|
|
603
|
+
if (opsExecuted) {
|
|
604
|
+
console.log('')
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
messagesHistory.push({ role: 'user', content: input })
|
|
608
|
+
messagesHistory.push({ role: 'assistant', content: responseText })
|
|
609
|
+
|
|
610
|
+
rl.prompt()
|
|
611
|
+
})
|
|
612
|
+
})
|
|
613
|
+
|
|
614
|
+
rl.on('close', () => {
|
|
615
|
+
console.log(dim('\nGoodbye!'))
|
|
616
|
+
process.exit(0)
|
|
617
|
+
})
|
|
351
618
|
}
|
|
352
619
|
|
|
353
|
-
//
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
620
|
+
// --- ENTRY POINT ---
|
|
621
|
+
function main() {
|
|
622
|
+
const args = process.argv.slice(2)
|
|
623
|
+
|
|
624
|
+
const state = {
|
|
625
|
+
apiUrl: DEFAULT_API_URL,
|
|
626
|
+
currentModel: DEFAULT_MODEL
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
// Parse direct flags
|
|
630
|
+
if (args.includes('-v') || args.includes('--version')) {
|
|
631
|
+
console.log('PRITUS CODE v' + VERSION)
|
|
632
|
+
process.exit(0)
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
if (args.includes('-h') || args.includes('--help')) {
|
|
636
|
+
console.log('PRITUS CODE v' + VERSION + ' - Terminal AI Coding Agent')
|
|
637
|
+
console.log('\nUsage:')
|
|
638
|
+
console.log(' prituscode Start interactive terminal session')
|
|
639
|
+
console.log(' prituscode "build a server" Run single prompt')
|
|
640
|
+
console.log(' prituscode -m ultra "query" Run single prompt with specified model')
|
|
641
|
+
console.log(' prituscode -v, --version Show version')
|
|
642
|
+
console.log(' prituscode -h, --help Show help')
|
|
643
|
+
process.exit(0)
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
let modelOverride = null
|
|
647
|
+
const queryArgs = []
|
|
648
|
+
|
|
649
|
+
for (let i = 0; i < args.length; i++) {
|
|
650
|
+
if (args[i] === '-m' || args[i] === '--model') {
|
|
651
|
+
if (i + 1 < args.length) {
|
|
652
|
+
modelOverride = args[i + 1]
|
|
653
|
+
i++
|
|
654
|
+
}
|
|
655
|
+
} else {
|
|
656
|
+
queryArgs.push(args[i])
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
if (modelOverride) {
|
|
661
|
+
const info = getModelInfo(modelOverride)
|
|
662
|
+
state.currentModel = info.id
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
// Non-interactive single prompt mode
|
|
666
|
+
if (queryArgs.length > 0) {
|
|
667
|
+
const singlePrompt = queryArgs.join(' ')
|
|
668
|
+
process.stdout.write(dim('Processing request...\n'))
|
|
669
|
+
sendChatRequest(state.apiUrl, state.currentModel, singlePrompt, [], (err, responseText) => {
|
|
670
|
+
if (err) {
|
|
671
|
+
console.error('\x1b[31mError: ' + err.message + '\x1b[39m')
|
|
672
|
+
process.exit(1)
|
|
673
|
+
}
|
|
674
|
+
console.log(responseText)
|
|
675
|
+
processFileOperations(responseText)
|
|
676
|
+
process.exit(0)
|
|
677
|
+
})
|
|
678
|
+
return
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
// Interactive mode startup
|
|
682
|
+
renderHeader()
|
|
683
|
+
renderWelcomeBox(process.cwd())
|
|
684
|
+
renderTips()
|
|
685
|
+
|
|
686
|
+
promptModelSelection(state.currentModel, (selectedModel) => {
|
|
687
|
+
state.currentModel = selectedModel
|
|
688
|
+
renderStatusBar(state.currentModel, process.cwd())
|
|
689
|
+
startRepl(state)
|
|
690
|
+
})
|
|
691
|
+
}
|
|
358
692
|
|
|
359
|
-
main()
|
|
693
|
+
main()
|
package/README.md
DELETED
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
# PRITUS CODE CLI
|
|
2
|
-
|
|
3
|
-
**Terminal-based AI coding assistant.** Local Vision Intelligence in your terminal.
|
|
4
|
-
|
|
5
|
-
## Install
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
# Install globally
|
|
9
|
-
npm install -g prituscode
|
|
10
|
-
|
|
11
|
-
# Or run directly with npx (no install needed)
|
|
12
|
-
npx prituscode
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
## Usage
|
|
16
|
-
|
|
17
|
-
### Interactive mode
|
|
18
|
-
```bash
|
|
19
|
-
prituscode
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
### One-shot mode
|
|
23
|
-
```bash
|
|
24
|
-
prituscode "build a responsive navbar with Tailwind"
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
### Custom endpoint
|
|
28
|
-
```bash
|
|
29
|
-
prituscode --endpoint https://your-pritus-deployment.com
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
### Select model tier
|
|
33
|
-
```bash
|
|
34
|
-
prituscode --model thinking
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
## Commands (interactive mode)
|
|
38
|
-
|
|
39
|
-
| Command | Description |
|
|
40
|
-
|---------|-------------|
|
|
41
|
-
| `/help` | Show available commands |
|
|
42
|
-
| `/clear` | Clear conversation history |
|
|
43
|
-
| `/model` | Switch model tier (`flash` / `pro` / `thinking`) |
|
|
44
|
-
| `/status` | Show connection status |
|
|
45
|
-
| `/exit` | Exit the CLI |
|
|
46
|
-
|
|
47
|
-
## Environment Variables
|
|
48
|
-
|
|
49
|
-
| Variable | Default | Description |
|
|
50
|
-
|----------|---------|-------------|
|
|
51
|
-
| `PRITUS_API_URL` | `https://pritusai.netlify.app` | API endpoint |
|
|
52
|
-
| `PRITUS_MODEL` | `pro` | Default model tier |
|
|
53
|
-
|
|
54
|
-
## Run without installing
|
|
55
|
-
|
|
56
|
-
```bash
|
|
57
|
-
# Clone and run directly
|
|
58
|
-
git clone https://github.com/sarthaksahoo/pritus-ai
|
|
59
|
-
cd pritus-ai/cli
|
|
60
|
-
node prituscode.js
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
## Publish to npm
|
|
64
|
-
|
|
65
|
-
```bash
|
|
66
|
-
npm login # log in to your npm account
|
|
67
|
-
cd cli
|
|
68
|
-
npm publish
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
After publishing, anyone can run `npx prituscode` globally.
|
|
72
|
-
|
|
73
|
-
## Requirements
|
|
74
|
-
|
|
75
|
-
- Node.js 18+ (for built-in `fetch`)
|
|
76
|
-
|
|
77
|
-
## License
|
|
78
|
-
|
|
79
|
-
MIT © Sarthak Sahoo
|