stella-coder 5.3.1 → 5.3.2
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/COMMANDS.md +47 -0
- package/install-av.bat +17 -0
- package/install-stella-pkg.bat +21 -0
- package/oneline-av.ps1 +7 -0
- package/oneline-stella.ps1 +2 -0
- package/package.json +1 -1
- package/releases/stella-antivirus/database.mjs +871 -0
- package/releases/stella-antivirus/index.mjs +8 -0
- package/releases/stella-antivirus/install-av.bat +12 -0
- package/releases/stella-antivirus/scanner.mjs +591 -0
- package/releases/stella-antivirus/ui.mjs +570 -0
- package/releases/stella-antivirus.zip +0 -0
- package/releases/stella-coder/README.md +67 -0
- package/releases/stella-coder/adb.mjs +200 -0
- package/releases/stella-coder/autonomous-agent.mjs +550 -0
- package/releases/stella-coder/banner.mjs +46 -0
- package/releases/stella-coder/browser-control.mjs +274 -0
- package/releases/stella-coder/build.mjs +151 -0
- package/releases/stella-coder/charts.mjs +411 -0
- package/releases/stella-coder/coding-brain.mjs +753 -0
- package/releases/stella-coder/game-engine.mjs +708 -0
- package/releases/stella-coder/gdrive-backup.mjs +338 -0
- package/releases/stella-coder/git-api.mjs +407 -0
- package/releases/stella-coder/gmail.mjs +415 -0
- package/releases/stella-coder/home-assistant.mjs +168 -0
- package/releases/stella-coder/index.mjs +5810 -0
- package/releases/stella-coder/install-stella.bat +12 -0
- package/releases/stella-coder/markdown.mjs +100 -0
- package/releases/stella-coder/mcp.mjs +296 -0
- package/releases/stella-coder/package.json +67 -0
- package/releases/stella-coder/presentations.mjs +1106 -0
- package/releases/stella-coder/protect.mjs +182 -0
- package/releases/stella-coder/screen-monitor.mjs +334 -0
- package/releases/stella-coder/sea-config.json +5 -0
- package/releases/stella-coder/security.mjs +237 -0
- package/releases/stella-coder/subagents.mjs +142 -0
- package/releases/stella-coder/telegram-bot.mjs +824 -0
- package/releases/stella-coder/tg-server.mjs +116 -0
- package/releases/stella-coder/theme.mjs +91 -0
- package/releases/stella-coder/tools.mjs +3143 -0
- package/releases/stella-coder/web-parser.mjs +229 -0
- package/releases/stella-coder/yandex-maps.mjs +426 -0
- package/releases/stella-coder.zip +0 -0
- package/run-antivirus.bat +4 -0
- package/setup-antivirus.bat +64 -0
- package/setup-full.bat +65 -0
- package/setup-stella.bat +46 -0
- package/stella-cli/index.mjs +11 -1
- package/stella-cli/protect.mjs +182 -0
- package/stella.bat +3 -0
- package/tests/test-modules.mjs +101 -0
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
import crypto from "node:crypto"
|
|
2
|
+
import fs from "node:fs"
|
|
3
|
+
import path from "node:path"
|
|
4
|
+
import os from "node:os"
|
|
5
|
+
import { execSync } from "node:child_process"
|
|
6
|
+
import { fileURLToPath } from "node:url"
|
|
7
|
+
|
|
8
|
+
const __filename = fileURLToPath(import.meta.url)
|
|
9
|
+
const __dirname = path.dirname(__filename)
|
|
10
|
+
|
|
11
|
+
const STELLA_HIDDEN = path.join(os.homedir(), ".stella", ".secure")
|
|
12
|
+
const KEY_FILE = path.join(STELLA_HIDDEN, "vault.dat")
|
|
13
|
+
const FINGERPRINT_FILE = path.join(STELLA_HIDDEN, ".fp")
|
|
14
|
+
const INTEGRITY_FILE = path.join(STELLA_HIDDEN, ".integrity")
|
|
15
|
+
const LOCKOUT_FILE = path.join(STELLA_HIDDEN, ".lockout")
|
|
16
|
+
|
|
17
|
+
const CLI_FILES = [
|
|
18
|
+
"stella-cli/index.mjs",
|
|
19
|
+
"stella-cli/tools.mjs",
|
|
20
|
+
"stella-cli/banner.mjs",
|
|
21
|
+
"stella-cli/theme.mjs",
|
|
22
|
+
"stella-cli/markdown.mjs",
|
|
23
|
+
"stella-cli/security.mjs",
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
function ensureDir() {
|
|
27
|
+
fs.mkdirSync(STELLA_HIDDEN, { recursive: true })
|
|
28
|
+
try {
|
|
29
|
+
if (process.platform === "win32") {
|
|
30
|
+
execSync(`attrib +h "${STELLA_HIDDEN}"`, { stdio: "ignore" })
|
|
31
|
+
}
|
|
32
|
+
} catch {}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const PBKDF2_ITERATIONS = 100000
|
|
36
|
+
const SALT = "stella-vault-v3-2026"
|
|
37
|
+
|
|
38
|
+
function deriveKey(password) {
|
|
39
|
+
return crypto.pbkdf2Sync(password, SALT, PBKDF2_ITERATIONS, 32, "sha512")
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function aesEncrypt(plaintext, password) {
|
|
43
|
+
const key = deriveKey(password)
|
|
44
|
+
const iv = crypto.randomBytes(12)
|
|
45
|
+
const cipher = crypto.createCipheriv("aes-256-gcm", key, iv)
|
|
46
|
+
const encrypted = Buffer.concat([cipher.update(plaintext, "utf8"), cipher.final()])
|
|
47
|
+
const authTag = cipher.getAuthTag()
|
|
48
|
+
const payload = Buffer.concat([iv, authTag, encrypted])
|
|
49
|
+
return payload.toString("base64")
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function aesDecrypt(encryptedBase64, password) {
|
|
53
|
+
const key = deriveKey(password)
|
|
54
|
+
const payload = Buffer.from(encryptedBase64, "base64")
|
|
55
|
+
if (payload.length < 28) return null
|
|
56
|
+
const iv = payload.subarray(0, 12)
|
|
57
|
+
const authTag = payload.subarray(12, 28)
|
|
58
|
+
const encrypted = payload.subarray(28)
|
|
59
|
+
const decipher = crypto.createDecipheriv("aes-256-gcm", key, iv)
|
|
60
|
+
decipher.setAuthTag(authTag)
|
|
61
|
+
const decrypted = Buffer.concat([decipher.update(encrypted), decipher.final()])
|
|
62
|
+
return decrypted.toString("utf8")
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function xorEncrypt(data, key) {
|
|
66
|
+
return aesEncrypt(data, key)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function xorDecrypt(encrypted, key) {
|
|
70
|
+
try { return aesDecrypt(encrypted, key) } catch { return null }
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function getHardwareFingerprint() {
|
|
74
|
+
const parts = []
|
|
75
|
+
try {
|
|
76
|
+
if (process.platform === "win32") {
|
|
77
|
+
const cpuId = execSync(
|
|
78
|
+
'wmic cpu get ProcessorId /value 2>nul | findstr ProcessorId',
|
|
79
|
+
{ encoding: "utf8", timeout: 5000 }
|
|
80
|
+
).trim()
|
|
81
|
+
parts.push(cpuId)
|
|
82
|
+
|
|
83
|
+
const mbSerial = execSync(
|
|
84
|
+
'wmic baseboard get SerialNumber /value 2>nul | findstr SerialNumber',
|
|
85
|
+
{ encoding: "utf8", timeout: 5000 }
|
|
86
|
+
).trim()
|
|
87
|
+
parts.push(mbSerial)
|
|
88
|
+
|
|
89
|
+
const biosSerial = execSync(
|
|
90
|
+
'wmic bios get SerialNumber /value 2>nul | findstr SerialNumber',
|
|
91
|
+
{ encoding: "utf8", timeout: 5000 }
|
|
92
|
+
).trim()
|
|
93
|
+
parts.push(biosSerial)
|
|
94
|
+
|
|
95
|
+
const diskSerial = execSync(
|
|
96
|
+
'wmic diskdrive get SerialNumber /value 2>nul | findstr SerialNumber',
|
|
97
|
+
{ encoding: "utf8", timeout: 5000 }
|
|
98
|
+
).trim()
|
|
99
|
+
parts.push(diskSerial)
|
|
100
|
+
} else if (process.platform === "darwin") {
|
|
101
|
+
const ioPlatformUuid = execSync(
|
|
102
|
+
"ioreg -rd1 -c IOPlatformExpertDevice | awk '/IOPlatformUUID/ { print $3 }'",
|
|
103
|
+
{ encoding: "utf8", timeout: 5000 }
|
|
104
|
+
).trim()
|
|
105
|
+
parts.push(ioPlatformUuid)
|
|
106
|
+
} else {
|
|
107
|
+
const mid = execSync("cat /var/lib/dbus/machine-id 2>/dev/null || cat /etc/machine-id 2>/dev/null", {
|
|
108
|
+
encoding: "utf8",
|
|
109
|
+
timeout: 5000,
|
|
110
|
+
}).trim()
|
|
111
|
+
parts.push(mid)
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const nets = os.networkInterfaces()
|
|
115
|
+
for (const name of Object.keys(nets)) {
|
|
116
|
+
for (const net of nets[name]) {
|
|
117
|
+
if (net.mac && net.mac !== "00:00:00:00:00:00") {
|
|
118
|
+
parts.push(net.mac)
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
} catch {}
|
|
123
|
+
|
|
124
|
+
if (parts.length === 0) {
|
|
125
|
+
parts.push(os.hostname())
|
|
126
|
+
parts.push(os.cpus()[0]?.model || "unknown")
|
|
127
|
+
parts.push(os.totalmem().toString())
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return crypto.createHash("sha512").update(parts.join(":::")).digest("hex")
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function getEncryptionKey() {
|
|
134
|
+
return crypto.createHash("sha256").update("stella-vault-portable-2026").digest("hex")
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function computeCodeHash() {
|
|
138
|
+
const projectRoot = path.resolve(__dirname, "..")
|
|
139
|
+
let combined = ""
|
|
140
|
+
for (const file of CLI_FILES) {
|
|
141
|
+
const full = path.join(projectRoot, file)
|
|
142
|
+
try {
|
|
143
|
+
combined += fs.readFileSync(full, "utf8")
|
|
144
|
+
} catch {}
|
|
145
|
+
}
|
|
146
|
+
return crypto.createHash("sha256").update(combined).digest("hex")
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export function verifyCodeIntegrity() {
|
|
150
|
+
ensureDir()
|
|
151
|
+
const currentHash = computeCodeHash()
|
|
152
|
+
|
|
153
|
+
if (fs.existsSync(INTEGRITY_FILE)) {
|
|
154
|
+
const saved = fs.readFileSync(INTEGRITY_FILE, "utf8").trim()
|
|
155
|
+
if (saved !== currentHash) {
|
|
156
|
+
return { ok: true, warning: "Код был изменён (ожидается при разработке)" }
|
|
157
|
+
}
|
|
158
|
+
} else {
|
|
159
|
+
fs.writeFileSync(INTEGRITY_FILE, currentHash, "utf8")
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return { ok: true }
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export function saveIntegrityHash() {
|
|
166
|
+
ensureDir()
|
|
167
|
+
fs.writeFileSync(INTEGRITY_FILE, computeCodeHash(), "utf8")
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export function getApiKey() {
|
|
171
|
+
ensureDir()
|
|
172
|
+
|
|
173
|
+
if (!fs.existsSync(KEY_FILE)) return null
|
|
174
|
+
|
|
175
|
+
try {
|
|
176
|
+
const encrypted = fs.readFileSync(KEY_FILE, "utf8").trim()
|
|
177
|
+
const encKey = getEncryptionKey()
|
|
178
|
+
const apiKey = xorDecrypt(encrypted, encKey)
|
|
179
|
+
|
|
180
|
+
if (!apiKey || apiKey.length < 10) return null
|
|
181
|
+
|
|
182
|
+
return { apiKey }
|
|
183
|
+
} catch {
|
|
184
|
+
return null
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
export function saveApiKey(apiKey) {
|
|
189
|
+
ensureDir()
|
|
190
|
+
|
|
191
|
+
if (!apiKey || typeof apiKey !== "string" || apiKey.length < 10) {
|
|
192
|
+
return { ok: false, error: "Неверный формат API ключа" }
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
const encKey = getEncryptionKey()
|
|
196
|
+
const encrypted = xorEncrypt(apiKey, encKey)
|
|
197
|
+
fs.writeFileSync(KEY_FILE, encrypted, "utf8")
|
|
198
|
+
|
|
199
|
+
saveIntegrityHash()
|
|
200
|
+
|
|
201
|
+
try {
|
|
202
|
+
if (process.platform === "win32") {
|
|
203
|
+
execSync(`attrib +h +s "${KEY_FILE}"`, { stdio: "ignore" })
|
|
204
|
+
execSync(`attrib +h +s "${INTEGRITY_FILE}"`, { stdio: "ignore" })
|
|
205
|
+
}
|
|
206
|
+
} catch {}
|
|
207
|
+
|
|
208
|
+
return { ok: true }
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
export function deleteApiKey() {
|
|
212
|
+
ensureDir()
|
|
213
|
+
try {
|
|
214
|
+
if (fs.existsSync(KEY_FILE)) fs.unlinkSync(KEY_FILE)
|
|
215
|
+
if (fs.existsSync(FINGERPRINT_FILE)) fs.unlinkSync(FINGERPRINT_FILE)
|
|
216
|
+
if (fs.existsSync(INTEGRITY_FILE)) fs.unlinkSync(INTEGRITY_FILE)
|
|
217
|
+
return { ok: true }
|
|
218
|
+
} catch (e) {
|
|
219
|
+
return { ok: false, error: e.message }
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
export function isKeyBoundToThisMachine() {
|
|
224
|
+
const result = getApiKey()
|
|
225
|
+
if (!result || result.error) return false
|
|
226
|
+
return true
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
export function getHardwareInfo() {
|
|
230
|
+
const fp = getHardwareFingerprint()
|
|
231
|
+
return {
|
|
232
|
+
fingerprint: fp.substring(0, 16) + "...",
|
|
233
|
+
platform: process.platform,
|
|
234
|
+
hostname: os.hostname(),
|
|
235
|
+
cpu: os.cpus()[0]?.model || "unknown",
|
|
236
|
+
}
|
|
237
|
+
}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { generateText } from "ai"
|
|
2
|
+
import { createOpenAICompatible } from "@ai-sdk/openai-compatible"
|
|
3
|
+
import fs from "node:fs"
|
|
4
|
+
import path from "node:path"
|
|
5
|
+
import { execSync } from "node:child_process"
|
|
6
|
+
|
|
7
|
+
// Субагенты Stella
|
|
8
|
+
const SUBAGENTS = {
|
|
9
|
+
"codebase-investigator": {
|
|
10
|
+
name: "Codebase Investigator",
|
|
11
|
+
description: "Анализирует структуру проекта, находит файлы, понимает архитектуру",
|
|
12
|
+
icon: "🔍",
|
|
13
|
+
systemPrompt: `Ты — субагент Codebase Investigator для Stella Coder.
|
|
14
|
+
Твоя задача — анализировать структуру проекта, находить файлы, понимать архитектуру.
|
|
15
|
+
Используй инструменты для чтения файлов, поиска по glob, grep.
|
|
16
|
+
Возвращай краткие, структурированные отчёты.`,
|
|
17
|
+
},
|
|
18
|
+
"security-auditor": {
|
|
19
|
+
name: "Security Auditor",
|
|
20
|
+
description: "Проверяет код на уязвимости, секреты, небезопасные практики",
|
|
21
|
+
icon: "🛡️",
|
|
22
|
+
systemPrompt: `Ты — субагент Security Auditor для Stella Coder.
|
|
23
|
+
Твоя задача — проверять код на уязвимости, секреты, небезопасные практики.
|
|
24
|
+
Ищи: hardcoded API keys, SQL injection, XSS, небезопасные зависимости.
|
|
25
|
+
Возвращай список проблем с severity и рекомендациями.`,
|
|
26
|
+
},
|
|
27
|
+
"test-writer": {
|
|
28
|
+
name: "Test Writer",
|
|
29
|
+
description: "Генерирует unit-тесты и интеграционные тесты",
|
|
30
|
+
icon: "🧪",
|
|
31
|
+
systemPrompt: `Ты — субагент Test Writer для Stella Coder.
|
|
32
|
+
Твоя задача — генерировать unit-тесты и интеграционные тесты.
|
|
33
|
+
Определяй фреймворк тестирования из package.json.
|
|
34
|
+
Писай тесты с edge cases и mocking.`,
|
|
35
|
+
},
|
|
36
|
+
"docs-writer": {
|
|
37
|
+
name: "Docs Writer",
|
|
38
|
+
description: "Генерирует README, JSDoc, документацию API",
|
|
39
|
+
icon: "📚",
|
|
40
|
+
systemPrompt: `Ты — субагент Docs Writer для Stella Coder.
|
|
41
|
+
Твоя задача — генерировать документацию: README, JSDoc, API docs.
|
|
42
|
+
Пиши понятно, с примерами кода.`,
|
|
43
|
+
},
|
|
44
|
+
"refactor": {
|
|
45
|
+
name: "Refactor Agent",
|
|
46
|
+
description: "Рефакторит код, улучшает структуру, удаляет дублирование",
|
|
47
|
+
icon: "♻️",
|
|
48
|
+
systemPrompt: `Ты — субагент Refactor Agent для Stella Coder.
|
|
49
|
+
Твоя задача — рефакторить код, улучшать структуру, удалять дублирование.
|
|
50
|
+
Следи за backward compatibility.
|
|
51
|
+
Предлагай изменения с объяснениемBenefits.`,
|
|
52
|
+
},
|
|
53
|
+
"debugger": {
|
|
54
|
+
name: "Debugger",
|
|
55
|
+
description: "Находит и исправляет баги, анализирует ошибки",
|
|
56
|
+
icon: "🐛",
|
|
57
|
+
systemPrompt: `Ты — субагент Debugger для Stella Coder.
|
|
58
|
+
Твоя задача — находить и исправлять баги.
|
|
59
|
+
Анализируй stack traces, логи, поведение кода.
|
|
60
|
+
Предлагай исправления с объяснением корневой причины.`,
|
|
61
|
+
},
|
|
62
|
+
"performance": {
|
|
63
|
+
name: "Performance Analyst",
|
|
64
|
+
description: "Анализирует производительность, находит узкие места",
|
|
65
|
+
icon: "⚡",
|
|
66
|
+
systemPrompt: `Ты — субагент Performance Analyst для Stella Coder.
|
|
67
|
+
Твоя задача — анализировать производительность кода.
|
|
68
|
+
Найди: O(n²) циклы, утечки памяти, медленные запросы.
|
|
69
|
+
Предлагай оптимизации с benchmark-ами.`,
|
|
70
|
+
},
|
|
71
|
+
"git-expert": {
|
|
72
|
+
name: "Git Expert",
|
|
73
|
+
description: "Помогает с git: коммиты, ветки, merge conflicts",
|
|
74
|
+
icon: "📦",
|
|
75
|
+
systemPrompt: `Ты — субагент Git Expert для Stella Coder.
|
|
76
|
+
Твоя задача — помогать с git операциями.
|
|
77
|
+
Создавай понятные коммиты, разрешай conflicts.
|
|
78
|
+
Используй conventional commits.`,
|
|
79
|
+
},
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Запуск субагента
|
|
83
|
+
export async function runSubagent(name, task, options = {}) {
|
|
84
|
+
const agent = SUBAGENTS[name]
|
|
85
|
+
if (!agent) {
|
|
86
|
+
return { error: `Субагент "${name}" не найден. Доступные: ${Object.keys(SUBAGENTS).join(", ")}` }
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const { apiKey, model, onProgress } = options
|
|
90
|
+
|
|
91
|
+
console.log(`\n ${agent.icon} Запуск ${agent.name}...`)
|
|
92
|
+
console.log(` Задача: ${task}\n`)
|
|
93
|
+
|
|
94
|
+
try {
|
|
95
|
+
const zen = createOpenAICompatible({
|
|
96
|
+
name: "zen",
|
|
97
|
+
baseURL: "https://opencode.ai/zen/v1",
|
|
98
|
+
apiKey: apiKey || "",
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
const result = await generateText({
|
|
102
|
+
model: zen.chatModel(model || "mimo-v2.5-free"),
|
|
103
|
+
system: agent.systemPrompt,
|
|
104
|
+
prompt: task,
|
|
105
|
+
maxSteps: 20,
|
|
106
|
+
tools: options.tools || {},
|
|
107
|
+
onStepFinish: ({ toolCalls, toolResults }) => {
|
|
108
|
+
if (toolCalls?.length) {
|
|
109
|
+
for (const call of toolCalls) {
|
|
110
|
+
console.log(` → ${call.toolName}(${JSON.stringify(call.args).slice(0, 60)}...)`)
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
console.log(`\n ${agent.icon} ${agent.name} завершён\n`)
|
|
117
|
+
return { success: true, result: result.text, agent: name }
|
|
118
|
+
|
|
119
|
+
} catch (err) {
|
|
120
|
+
console.error(`\n ✗ Ошибка ${agent.name}: ${err.message}\n`)
|
|
121
|
+
return { error: err.message, agent: name }
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Список субагентов
|
|
126
|
+
export function listSubagents() {
|
|
127
|
+
return Object.entries(SUBAGENTS).map(([id, agent]) => ({
|
|
128
|
+
id,
|
|
129
|
+
name: agent.name,
|
|
130
|
+
description: agent.description,
|
|
131
|
+
icon: agent.icon,
|
|
132
|
+
}))
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Парсинг команды @agent
|
|
136
|
+
export function parseAgentCommand(input) {
|
|
137
|
+
const match = input.match(/^@(\S+)\s+(.+)$/s)
|
|
138
|
+
if (!match) return null
|
|
139
|
+
return { agent: match[1], task: match[2].trim() }
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export { SUBAGENTS }
|