primocode 1.1.0 → 4.1.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/lib/config.js CHANGED
@@ -1,71 +1,76 @@
1
- // Configuracao PrimoCode
2
-
3
- 'use strict';
4
-
5
- const fs = require('fs');
6
- const path = require('path');
7
- const os = require('os');
8
-
9
- const HOME = os.homedir();
10
- const CONFIG_DIR = path.join(HOME, '.primocode');
11
- const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
12
- const HISTORY_FILE = path.join(CONFIG_DIR, 'history.jsonl');
13
-
14
- function ensureDir() {
15
- try { fs.mkdirSync(CONFIG_DIR, { recursive: true }); } catch {}
16
- }
17
-
18
- // Mapeamento de modos para modelos do servidor
19
- const MODEL_MAP = {
20
- 'Conecta Primo AI': 'main',
21
- 'Chat': 'fast',
22
- 'JARVIS': 'main',
23
- 'primocode': 'main',
24
- 'chat': 'fast',
25
- };
26
-
27
- // Resolve o modelo correto baseado no modo
28
- function resolveModel(mode) {
29
- return MODEL_MAP[mode] || MODEL_MAP['Conecta Primo AI'];
30
- }
31
-
32
- function loadConfig() {
33
- ensureDir();
34
- let file = {};
35
- try {
36
- if (fs.existsSync(CONFIG_FILE)) file = JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8'));
37
- } catch { file = {}; }
38
-
39
- const mode = process.env.PRIMOCODE_MODE || file.mode || 'Conecta Primo AI';
40
- // Modelo SEMPRE derivado do modo — nunca usa file.model diretamente
41
- const model = resolveModel(mode);
42
-
43
- return {
44
- server: process.env.PRIMOCODE_SERVER || file.server || 'https://primocode-server.onrender.com',
45
- model: model,
46
- mode: mode,
47
- autoApply: file.autoApply === true,
48
- _file: file,
49
- };
50
- }
51
-
52
- function saveConfig(partial) {
53
- ensureDir();
54
- const cur = (() => { try { return JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8')); } catch { return {}; } })();
55
- const next = { ...cur, ...partial };
56
- // Se salvou um modo novo, atualiza o modelo tambem
57
- if (partial.mode && MODEL_MAP[partial.mode]) {
58
- next.model = MODEL_MAP[partial.mode];
59
- }
60
- fs.writeFileSync(CONFIG_FILE, JSON.stringify(next, null, 2), 'utf8');
61
- return next;
62
- }
63
-
64
- function appendHistory(entry) {
65
- ensureDir();
66
- try {
67
- fs.appendFileSync(HISTORY_FILE, JSON.stringify({ ts: Date.now(), ...entry }) + '\n', 'utf8');
68
- } catch {}
69
- }
70
-
71
- module.exports = { loadConfig, saveConfig, appendHistory, resolveModel, CONFIG_DIR, CONFIG_FILE, HISTORY_FILE, MODEL_MAP };
1
+ // Configuracao PrimoCode — Cross-Platform (Windows, macOS, Linux, Termux)
2
+
3
+ 'use strict';
4
+
5
+ const fs = require('fs');
6
+ const path = require('path');
7
+ const os = require('os');
8
+
9
+ // Detecta Termux (Android)
10
+ function isTermux() {
11
+ return process.env.TERMUX_VERSION !== undefined ||
12
+ process.env.PREFIX?.includes('termux') ||
13
+ process.env.HOME?.includes('termux');
14
+ }
15
+
16
+ // Diretório base
17
+ const HOME = isTermux() ? '/data/data/com.termux/files/home' : os.homedir();
18
+ const CONFIG_DIR = path.join(HOME, '.primocode');
19
+ const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
20
+ const HISTORY_FILE = path.join(CONFIG_DIR, 'history.jsonl');
21
+
22
+ function ensureDir() {
23
+ try { fs.mkdirSync(CONFIG_DIR, { recursive: true }); } catch {}
24
+ }
25
+
26
+ // Mapeamento de modos para modelos do servidor
27
+ const MODEL_MAP = {
28
+ 'Primo Code': 'main',
29
+ 'Chat': 'fast',
30
+ 'chat': 'fast',
31
+ };
32
+
33
+ // Resolve o modelo correto baseado no modo
34
+ function resolveModel(mode) {
35
+ return MODEL_MAP[mode] || MODEL_MAP['Primo Code'];
36
+ }
37
+
38
+ function loadConfig() {
39
+ ensureDir();
40
+ let file = {};
41
+ try {
42
+ if (fs.existsSync(CONFIG_FILE)) file = JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8'));
43
+ } catch { file = {}; }
44
+
45
+ const mode = process.env.PRIMOCODE_MODE || file.mode || 'Primo Code';
46
+ const model = resolveModel(mode);
47
+
48
+ return {
49
+ server: process.env.PRIMOCODE_SERVER || file.server || 'https://primocode-server.onrender.com',
50
+ model: model,
51
+ mode: mode,
52
+ autoApply: file.autoApply === true,
53
+ isTermux: isTermux(),
54
+ _file: file,
55
+ };
56
+ }
57
+
58
+ function saveConfig(partial) {
59
+ ensureDir();
60
+ const cur = (() => { try { return JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8')); } catch { return {}; } })();
61
+ const next = { ...cur, ...partial };
62
+ if (partial.mode && MODEL_MAP[partial.mode]) {
63
+ next.model = MODEL_MAP[partial.mode];
64
+ }
65
+ fs.writeFileSync(CONFIG_FILE, JSON.stringify(next, null, 2), 'utf8');
66
+ return next;
67
+ }
68
+
69
+ function appendHistory(entry) {
70
+ ensureDir();
71
+ try {
72
+ fs.appendFileSync(HISTORY_FILE, JSON.stringify({ ts: Date.now(), ...entry }) + '\n', 'utf8');
73
+ } catch {}
74
+ }
75
+
76
+ module.exports = { loadConfig, saveConfig, appendHistory, resolveModel, isTermux, CONFIG_DIR, CONFIG_FILE, HISTORY_FILE, MODEL_MAP };
package/lib/mascot.js ADDED
@@ -0,0 +1,121 @@
1
+ // Mascote PrimoCode — animações ASCII conforme estado da IA
2
+ // Baseado no anexo do usuário: IDLE, THINKING, CODING, HAPPY
3
+
4
+ 'use strict';
5
+
6
+ const c = require('./ui').c;
7
+
8
+ // Frames do mascote (cada estado tem múltiplos frames para animação)
9
+ const FRAMES = {
10
+ idle: [
11
+ ` ╭─────────╮
12
+ │ ◠ ◠ │
13
+ │ ‿ │
14
+ ╰─────────╯`,
15
+ ` ╭─────────╮
16
+ │ ◠ ◠ │
17
+ │ ‿ │
18
+ ╰─────────╯`,
19
+ ],
20
+ thinking: [
21
+ ` ╭─────────╮
22
+ │ ◠ ◠ │
23
+ │ ‿ │
24
+ ╰────?────╯`,
25
+ ` ╭─────────╮
26
+ │ ◡ ◠ │
27
+ │ ‿ │
28
+ ╰────?────╯`,
29
+ ` ╭─────────╮
30
+ │ ◠ ◡ │
31
+ │ ‿ │
32
+ ╰────?────╯`,
33
+ ],
34
+ coding: [
35
+ ` ╭─────────╮
36
+ │ ◕ ◕ │
37
+ │ ‿ │
38
+ ╰──⌨️─────╯`,
39
+ ` ╭─────────╮
40
+ │ ◕ ◕ │
41
+ │ ‿ │
42
+ ╰───⌨️────╯`,
43
+ ` ╭─────────╮
44
+ │ ◕ ◕ │
45
+ │ ‿ │
46
+ ╰────⌨️───╯`,
47
+ ],
48
+ happy: [
49
+ ` ╭─────────╮
50
+ │ ◠ ◠ │
51
+ │ ▽ │
52
+ ╰─────────╯`,
53
+ ` ╭─────────╮
54
+ │ ◡ ◡ │
55
+ │ ▽ │
56
+ ╰─────────╯`,
57
+ ],
58
+ searching: [
59
+ ` ╭─────────╮
60
+ │ ◠ ◠ │
61
+ │ ‿ │
62
+ ╰──🔍─────╯`,
63
+ ` ╭─────────╮
64
+ │ ◠ ◠ │
65
+ │ ‿ │
66
+ ╰───🔍────╯`,
67
+ ],
68
+ mouse: [
69
+ ` ╭─────────╮
70
+ │ ◠ ◠ │
71
+ │ ‿ │
72
+ ╰──🖱️─────╯`,
73
+ ` ╭─────────╮
74
+ │ ◠ ◠ │
75
+ │ ‿ │
76
+ ╰────🖱️───╯`,
77
+ ],
78
+ };
79
+
80
+ let currentState = 'idle';
81
+ let currentFrame = 0;
82
+ let animationInterval = null;
83
+
84
+ function render(state = 'idle', message = '') {
85
+ const frames = FRAMES[state] || FRAMES.idle;
86
+ const frame = frames[currentFrame % frames.length];
87
+ const label = message ? ` ${c.muted(message)}` : '';
88
+ return `\n${c.brand(frame)}${label}\n`;
89
+ }
90
+
91
+ function setState(state, message = '') {
92
+ currentState = state;
93
+ currentFrame = 0;
94
+ return render(state, message);
95
+ }
96
+
97
+ function startAnimation(state, message = '', intervalMs = 500) {
98
+ currentState = state;
99
+ currentFrame = 0;
100
+ if (animationInterval) clearInterval(animationInterval);
101
+ animationInterval = setInterval(() => {
102
+ currentFrame++;
103
+ process.stdout.write('\x1b[2A\x1b[0J'); // sobe 2 linhas e limpa
104
+ process.stdout.write(render(currentState, message));
105
+ }, intervalMs);
106
+ }
107
+
108
+ function stopAnimation() {
109
+ if (animationInterval) {
110
+ clearInterval(animationInterval);
111
+ animationInterval = null;
112
+ }
113
+ }
114
+
115
+ function nextFrame(state, message = '') {
116
+ currentState = state;
117
+ currentFrame++;
118
+ return render(state, message);
119
+ }
120
+
121
+ module.exports = { render, setState, startAnimation, stopAnimation, nextFrame, FRAMES };
package/lib/memory.js ADDED
@@ -0,0 +1,179 @@
1
+ // Sistema de Memória e Projetos do PrimoCode
2
+ //
3
+ // Estrutura de pastas:
4
+ // Windows: C:\primocode\
5
+ // Linux/Mac: ~/primocode/
6
+ // Termux/Android: /storage/shared/primocode/ (acessível pelo usuário)
7
+ // ├── memory.md ← Memória geral do usuário
8
+ // ├── projeto-1\ ← Pasta de projeto
9
+ // │ ├── index.html
10
+ // │ ├── style.css
11
+ // │ └── primocode-projeto-1.md ← Memória do projeto
12
+ // └── projeto-2\
13
+ // └── ...
14
+
15
+ 'use strict';
16
+
17
+ const fs = require('fs');
18
+ const path = require('path');
19
+ const platform = require('./platform');
20
+
21
+ // Diretório principal de projetos (cross-platform)
22
+ const PRIMOCODE_DIR = platform.getProjectsDir();
23
+ const MEMORY_FILE = path.join(PRIMOCODE_DIR, 'memory.md');
24
+
25
+ function ensureDir(dir) {
26
+ try { fs.mkdirSync(dir, { recursive: true }); } catch {}
27
+ }
28
+
29
+ // Inicializa a estrutura de pastas
30
+ function init() {
31
+ ensureDir(PRIMOCODE_DIR);
32
+ if (!fs.existsSync(MEMORY_FILE)) {
33
+ fs.writeFileSync(MEMORY_FILE, `# Memória PrimoCode
34
+
35
+ ## Sobre o Usuário
36
+ - Nome:
37
+ - Preferências:
38
+
39
+ ## Estilo de Resposta Preferido
40
+ - Código sempre em arquivos, nunca no chat
41
+ - Abrir automaticamente no navegador quando aplicável
42
+ - Pesquisar na web para garantir qualidade
43
+
44
+ ## Projetos Anteriores
45
+ `, 'utf8');
46
+ }
47
+ }
48
+
49
+ // Carrega a memória geral
50
+ function loadMemory() {
51
+ init();
52
+ try {
53
+ return fs.readFileSync(MEMORY_FILE, 'utf8');
54
+ } catch {
55
+ return '';
56
+ }
57
+ }
58
+
59
+ // Salva na memória geral
60
+ function saveMemory(content) {
61
+ init();
62
+ fs.writeFileSync(MEMORY_FILE, content, 'utf8');
63
+ }
64
+
65
+ // Adiciona informação à memória
66
+ function appendMemory(section, info) {
67
+ const mem = loadMemory();
68
+ const sectionHeader = `## ${section}`;
69
+ const idx = mem.indexOf(sectionHeader);
70
+ if (idx >= 0) {
71
+ const before = mem.slice(0, idx + sectionHeader.length);
72
+ const after = mem.slice(idx + sectionHeader.length);
73
+ saveMemory(`${before}\n- ${info}${after}`);
74
+ } else {
75
+ saveMemory(`${mem}\n## ${section}\n- ${info}\n`);
76
+ }
77
+ }
78
+
79
+ // Lista todos os projetos existentes
80
+ function listProjects() {
81
+ init();
82
+ try {
83
+ const entries = fs.readdirSync(PRIMOCODE_DIR, { withFileTypes: true });
84
+ return entries
85
+ .filter(e => e.isDirectory())
86
+ .map(e => e.name);
87
+ } catch {
88
+ return [];
89
+ }
90
+ }
91
+
92
+ // Cria um novo projeto (pasta + arquivo de memória)
93
+ function createProject(projectName) {
94
+ init();
95
+ const safeName = projectName.replace(/[^a-zA-Z0-9\-_]/g, '-').toLowerCase();
96
+ const projectDir = path.join(PRIMOCODE_DIR, safeName);
97
+ ensureDir(projectDir);
98
+
99
+ const projectMemoryFile = path.join(projectDir, `primocode-${safeName}.md`);
100
+ if (!fs.existsSync(projectMemoryFile)) {
101
+ fs.writeFileSync(projectMemoryFile, `# PrimoCode — ${projectName}
102
+
103
+ ## Descrição
104
+ Projeto iniciado em ${new Date().toLocaleString('pt-BR')}
105
+
106
+ ## Contexto
107
+
108
+ ## Arquivos
109
+
110
+ ## Decisões Técnicas
111
+
112
+ ## Notas
113
+ `, 'utf8');
114
+ }
115
+
116
+ // Atualiza memória geral
117
+ appendMemory('Projetos Anteriores', `${safeName} — ${projectName} (${new Date().toLocaleDateString('pt-BR')})`);
118
+
119
+ return { dir: projectDir, name: safeName, memoryFile: projectMemoryFile };
120
+ }
121
+
122
+ // Carrega memória de um projeto
123
+ function loadProjectMemory(projectName) {
124
+ const safeName = projectName.replace(/[^a-zA-Z0-9\-_]/g, '-').toLowerCase();
125
+ const projectMemoryFile = path.join(PRIMOCODE_DIR, safeName, `primocode-${safeName}.md`);
126
+ try {
127
+ return fs.readFileSync(projectMemoryFile, 'utf8');
128
+ } catch {
129
+ return '';
130
+ }
131
+ }
132
+
133
+ // Salva memória de um projeto
134
+ function saveProjectMemory(projectName, content) {
135
+ const safeName = projectName.replace(/[^a-zA-Z0-9\-_]/g, '-').toLowerCase();
136
+ const projectDir = path.join(PRIMOCODE_DIR, safeName);
137
+ ensureDir(projectDir);
138
+ const projectMemoryFile = path.join(projectDir, `primocode-${safeName}.md`);
139
+ fs.writeFileSync(projectMemoryFile, content, 'utf8');
140
+ }
141
+
142
+ // Verifica se projeto existe
143
+ function projectExists(projectName) {
144
+ const safeName = projectName.replace(/[^a-zA-Z0-9\-_]/g, '-').toLowerCase();
145
+ return fs.existsSync(path.join(PRIMOCODE_DIR, safeName));
146
+ }
147
+
148
+ // Salva arquivo em um projeto
149
+ function saveProjectFile(projectName, filename, content) {
150
+ const safeName = projectName.replace(/[^a-zA-Z0-9\-_]/g, '-').toLowerCase();
151
+ const projectDir = path.join(PRIMOCODE_DIR, safeName);
152
+ ensureDir(projectDir);
153
+ const filePath = path.join(projectDir, filename);
154
+ fs.writeFileSync(filePath, content, 'utf8');
155
+
156
+ // Atualiza memória do projeto
157
+ const mem = loadProjectMemory(safeName);
158
+ if (!mem.includes(filename)) {
159
+ const updated = mem.replace('## Arquivos', `## Arquivos\n- ${filename}`);
160
+ saveProjectMemory(safeName, updated);
161
+ }
162
+
163
+ return filePath;
164
+ }
165
+
166
+ module.exports = {
167
+ PRIMOCODE_DIR,
168
+ MEMORY_FILE,
169
+ init,
170
+ loadMemory,
171
+ saveMemory,
172
+ appendMemory,
173
+ listProjects,
174
+ createProject,
175
+ loadProjectMemory,
176
+ saveProjectMemory,
177
+ projectExists,
178
+ saveProjectFile,
179
+ };
package/lib/mouse.js ADDED
@@ -0,0 +1,144 @@
1
+ // Mouse Virtual — controle completo da interface do computador
2
+ // Suporta: Windows, macOS, Linux, Termux (Android)
3
+
4
+ 'use strict';
5
+
6
+ const { execSync } = require('child_process');
7
+ const os = require('os');
8
+ const path = require('path');
9
+ const platform = require('./platform');
10
+
11
+ // Estado do mouse virtual
12
+ let mouseVisible = false;
13
+ let currentX = 0;
14
+ let currentY = 0;
15
+
16
+ // Mostra/esconde o cursor virtual no terminal
17
+ function showCursor(x, y) {
18
+ mouseVisible = true;
19
+ currentX = x;
20
+ currentY = y;
21
+ return { x, y, visible: true };
22
+ }
23
+
24
+ function hideCursor() {
25
+ mouseVisible = false;
26
+ return { visible: false };
27
+ }
28
+
29
+ // Move o mouse para coordenadas absolutas
30
+ async function moveTo(x, y) {
31
+ if (platform.isAndroid()) {
32
+ return platform.moveMouse(x, y);
33
+ }
34
+ try {
35
+ const p = process.platform;
36
+ if (p === 'win32') {
37
+ const ps = `Add-Type -AssemblyName System.Windows.Forms; [System.Windows.Forms.Cursor]::Position = New-Object System.Drawing.Point(${x}, ${y})`;
38
+ execSync(`powershell -Command "${ps}"`, { stdio: 'ignore' });
39
+ } else if (p === 'darwin') {
40
+ execSync(`cliclick m:${x},${y}`, { stdio: 'ignore' });
41
+ } else {
42
+ execSync(`xdotool mousemove ${x} ${y}`, { stdio: 'ignore' });
43
+ }
44
+ return showCursor(x, y);
45
+ } catch (e) {
46
+ return { ok: false, error: e.message };
47
+ }
48
+ }
49
+
50
+ // Clica em coordenadas específicas
51
+ async function clickAt(x, y, button = 'left') {
52
+ if (platform.isAndroid()) {
53
+ return platform.clickMouse(x, y);
54
+ }
55
+ try {
56
+ await moveTo(x, y);
57
+ const p = process.platform;
58
+ if (p === 'win32') {
59
+ const clickPs = `Add-Type -MemberDefinition '[DllImport(\"user32.dll\")] public static extern void mouse_event(int flags, int dx, int dy, int data, int extraInfo);' -Name Mouse -Namespace Win32; [Win32.Mouse]::mouse_event(0x02, 0, 0, 0, 0); [Win32.Mouse]::mouse_event(0x04, 0, 0, 0, 0)`;
60
+ execSync(`powershell -Command "${clickPs}"`, { stdio: 'ignore' });
61
+ } else if (p === 'darwin') {
62
+ execSync(`cliclick c:${x},${y}`, { stdio: 'ignore' });
63
+ } else {
64
+ execSync(`xdotool mousemove ${x} ${y} click 1`, { stdio: 'ignore' });
65
+ }
66
+ return { ok: true, x, y, button };
67
+ } catch (e) {
68
+ return { ok: false, error: e.message };
69
+ }
70
+ }
71
+
72
+ // Clica em um elemento pelo texto (via browser CDP)
73
+ async function clickText(text, browser) {
74
+ try {
75
+ const result = await browser.clickText(text);
76
+ return { ok: true, ...result };
77
+ } catch (e) {
78
+ return { ok: false, error: e.message };
79
+ }
80
+ }
81
+
82
+ // Clica em um seletor CSS (via browser CDP)
83
+ async function clickSelector(selector, browser) {
84
+ try {
85
+ const result = await browser.clickSelector(selector);
86
+ return { ok: true, ...result };
87
+ } catch (e) {
88
+ return { ok: false, error: e.message };
89
+ }
90
+ }
91
+
92
+ // Digita texto em um campo (via browser CDP)
93
+ async function typeIn(selector, text, browser) {
94
+ try {
95
+ const result = await browser.typeInSelector(selector, text);
96
+ return { ok: true, ...result };
97
+ } catch (e) {
98
+ return { ok: false, error: e.message };
99
+ }
100
+ }
101
+
102
+ // Pressiona uma tecla (via browser CDP)
103
+ async function pressKey(key, browser) {
104
+ try {
105
+ const result = await browser.key(key);
106
+ return { ok: true, ...result };
107
+ } catch (e) {
108
+ return { ok: false, error: e.message };
109
+ }
110
+ }
111
+
112
+ // Scroll em uma posição
113
+ async function scrollAt(x, y, dy, browser) {
114
+ try {
115
+ await browser.scroll(dy);
116
+ return { ok: true, dy };
117
+ } catch (e) {
118
+ return { ok: false, error: e.message };
119
+ }
120
+ }
121
+
122
+ // Tira screenshot da tela
123
+ async function screenshot(savePath) {
124
+ return platform.screenshot(savePath);
125
+ }
126
+
127
+ // Abre um aplicativo pelo nome
128
+ async function openApp(appName) {
129
+ return platform.openApp(appName);
130
+ }
131
+
132
+ module.exports = {
133
+ moveTo,
134
+ clickAt,
135
+ clickText,
136
+ clickSelector,
137
+ typeIn,
138
+ pressKey,
139
+ scrollAt,
140
+ screenshot,
141
+ openApp,
142
+ showCursor,
143
+ hideCursor,
144
+ };