stella-coder 5.3.0 → 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/game-engine.mjs +2 -2
- 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,550 @@
|
|
|
1
|
+
import { readFileSync, writeFileSync, mkdirSync, existsSync, appendFileSync } from "fs"
|
|
2
|
+
import { join } from "path"
|
|
3
|
+
import { homedir } from "os"
|
|
4
|
+
import { execSync } from "child_process"
|
|
5
|
+
|
|
6
|
+
const STELLA_DIR = join(homedir(), ".stella")
|
|
7
|
+
const AUTO_DIR = join(STELLA_DIR, "autonomous")
|
|
8
|
+
const MEMORY_FILE = join(AUTO_DIR, "memory.json")
|
|
9
|
+
const TASKS_FILE = join(AUTO_DIR, "tasks.json")
|
|
10
|
+
const LOG_FILE = join(AUTO_DIR, "activity.log")
|
|
11
|
+
const DASHBOARD_FILE = join(AUTO_DIR, "dashboard.html")
|
|
12
|
+
const STATE_FILE = join(AUTO_DIR, "state.json")
|
|
13
|
+
|
|
14
|
+
function ensureDir() {
|
|
15
|
+
if (!existsSync(AUTO_DIR)) mkdirSync(AUTO_DIR, { recursive: true })
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function loadJSON(file, fallback) {
|
|
19
|
+
try { return JSON.parse(readFileSync(file, "utf-8")) } catch { return fallback }
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function saveJSON(file, data) {
|
|
23
|
+
ensureDir()
|
|
24
|
+
writeFileSync(file, JSON.stringify(data, null, 2))
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function logEntry(action, details) {
|
|
28
|
+
ensureDir()
|
|
29
|
+
const entry = `[${new Date().toISOString()}] ${action}: ${details}\n`
|
|
30
|
+
appendFileSync(LOG_FILE, entry)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function shellRun(cmd) {
|
|
34
|
+
try {
|
|
35
|
+
execSync(cmd, { timeout: 60000, stdio: "pipe", shell: true })
|
|
36
|
+
return true
|
|
37
|
+
} catch { return false }
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export class AutonomousAgent {
|
|
41
|
+
constructor() {
|
|
42
|
+
ensureDir()
|
|
43
|
+
this.memory = loadJSON(MEMORY_FILE, { projects: [], accounts: [], videos: [], earnings: 0, lessons: [] })
|
|
44
|
+
this.tasks = loadJSON(TASKS_FILE, { queue: [], completed: [], failed: [] })
|
|
45
|
+
this.state = loadJSON(STATE_FILE, { running: false, startedAt: null, goal: "", pid: null, iterations: 0 })
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
save() {
|
|
49
|
+
saveJSON(MEMORY_FILE, this.memory)
|
|
50
|
+
saveJSON(TASKS_FILE, this.tasks)
|
|
51
|
+
saveJSON(STATE_FILE, this.state)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
planGoal(goal) {
|
|
55
|
+
const plan = {
|
|
56
|
+
id: Date.now().toString(36),
|
|
57
|
+
goal,
|
|
58
|
+
createdAt: new Date().toISOString(),
|
|
59
|
+
steps: [],
|
|
60
|
+
status: "planning"
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const g = goal.toLowerCase()
|
|
64
|
+
|
|
65
|
+
if (g.includes("видео") || g.includes("video")) {
|
|
66
|
+
plan.steps = [
|
|
67
|
+
{ id: "concept", name: "Create video concept and script", status: "pending", subtasks: [
|
|
68
|
+
"Write a compelling script/storyboard for the video",
|
|
69
|
+
"Create HTML presentation with animations showing the product",
|
|
70
|
+
"Add text overlays, transitions, and effects"
|
|
71
|
+
], results: [] },
|
|
72
|
+
{ id: "build_video", name: "Build HTML video/animation", status: "pending", subtasks: [
|
|
73
|
+
"Create self-contained HTML file with CSS animations",
|
|
74
|
+
"Add GSAP or CSS keyframe animations",
|
|
75
|
+
"Create cinematic transitions between scenes",
|
|
76
|
+
"Add background music placeholder"
|
|
77
|
+
], results: [] },
|
|
78
|
+
{ id: "export", name: "Export and place on desktop", status: "pending", subtasks: [
|
|
79
|
+
"Copy the HTML video file to Desktop",
|
|
80
|
+
"Create a .bat launcher to open it in browser",
|
|
81
|
+
"Create a poster/thumbnail image"
|
|
82
|
+
], results: [] },
|
|
83
|
+
{ id: "promote", name: "Promote the content", status: "pending", subtasks: [
|
|
84
|
+
"Create social media post templates",
|
|
85
|
+
"Write promotional text for sharing"
|
|
86
|
+
], results: [] }
|
|
87
|
+
]
|
|
88
|
+
} else if (g.includes("приложен") || g.includes("app") || g.includes("заработ") || g.includes("$") || g.includes("монетиз") || g.includes("donate") || g.includes("заработ")) {
|
|
89
|
+
plan.steps = [
|
|
90
|
+
{ id: "research", name: "Research market & competitors", status: "pending", subtasks: [
|
|
91
|
+
"Search for trending app ideas and niches",
|
|
92
|
+
"Analyze top competitors in the space",
|
|
93
|
+
"Define monetization strategy (ads, subscriptions, donations)"
|
|
94
|
+
], results: [] },
|
|
95
|
+
{ id: "architect", name: "Architecture & design", status: "pending", subtasks: [
|
|
96
|
+
"Choose tech stack (Next.js + Tailwind + Supabase)",
|
|
97
|
+
"Design database schema",
|
|
98
|
+
"Create API structure"
|
|
99
|
+
], results: [] },
|
|
100
|
+
{ id: "build", name: "Build the application", status: "pending", subtasks: [
|
|
101
|
+
"Create project with package.json, config files",
|
|
102
|
+
"Build frontend with UI components",
|
|
103
|
+
"Build backend API routes",
|
|
104
|
+
"Add Stripe/Paddle payment integration",
|
|
105
|
+
"Add donation button (Buy Me a Coffee / Ko-fi)",
|
|
106
|
+
"Add user authentication"
|
|
107
|
+
], results: [] },
|
|
108
|
+
{ id: "deploy", name: "Deploy to production", status: "pending", subtasks: [
|
|
109
|
+
"Initialize git repo, commit all files",
|
|
110
|
+
"Push to GitHub",
|
|
111
|
+
"Deploy frontend to Vercel",
|
|
112
|
+
"Deploy backend to Railway/Render",
|
|
113
|
+
"Configure custom domain if needed"
|
|
114
|
+
], results: [] },
|
|
115
|
+
{ id: "accounts", name: "Create promo accounts", status: "pending", subtasks: [
|
|
116
|
+
"Create YouTube channel for the project",
|
|
117
|
+
"Create TikTok account",
|
|
118
|
+
"Create Twitter/X account",
|
|
119
|
+
"Create Telegram channel",
|
|
120
|
+
"Create Product Hunt listing"
|
|
121
|
+
], results: [] },
|
|
122
|
+
{ id: "content", name: "Create promotional content", status: "pending", subtasks: [
|
|
123
|
+
"Write launch blog post",
|
|
124
|
+
"Create demo video script",
|
|
125
|
+
"Write Reddit posts for r/SideProject, r/webdev",
|
|
126
|
+
"Create Hacker News Show HN post",
|
|
127
|
+
"Write Product Hunt description"
|
|
128
|
+
], results: [] },
|
|
129
|
+
{ id: "dashboard", name: "Build management dashboard", status: "pending", subtasks: [
|
|
130
|
+
"Create HTML dashboard page",
|
|
131
|
+
"Add analytics tracking",
|
|
132
|
+
"Add financial metrics view",
|
|
133
|
+
"Add user management"
|
|
134
|
+
], results: [] },
|
|
135
|
+
{ id: "optimize", name: "Growth & optimization", status: "pending", subtasks: [
|
|
136
|
+
"SEO optimization",
|
|
137
|
+
"Performance audit",
|
|
138
|
+
"Add analytics (Google Analytics / Plausible)",
|
|
139
|
+
"Set up email list"
|
|
140
|
+
], results: [] }
|
|
141
|
+
]
|
|
142
|
+
} else if (g.includes("сайт") || g.includes("website") || g.includes("лендинг")) {
|
|
143
|
+
plan.steps = [
|
|
144
|
+
{ id: "design", name: "Design the website", status: "pending", subtasks: [
|
|
145
|
+
"Create wireframe and layout",
|
|
146
|
+
"Design UI with modern dark theme",
|
|
147
|
+
"Write compelling copy"
|
|
148
|
+
], results: [] },
|
|
149
|
+
{ id: "build", name: "Build the website", status: "pending", subtasks: [
|
|
150
|
+
"Create HTML/CSS/JS files",
|
|
151
|
+
"Add responsive design",
|
|
152
|
+
"Add animations and interactions"
|
|
153
|
+
], results: [] },
|
|
154
|
+
{ id: "seo", name: "SEO & performance", status: "pending", subtasks: [
|
|
155
|
+
"Add meta tags and Open Graph",
|
|
156
|
+
"Optimize images and loading",
|
|
157
|
+
"Add structured data"
|
|
158
|
+
], results: [] },
|
|
159
|
+
{ id: "deploy", name: "Deploy the website", status: "pending", subtasks: [
|
|
160
|
+
"Push to GitHub",
|
|
161
|
+
"Enable GitHub Pages or deploy to Vercel",
|
|
162
|
+
"Configure domain"
|
|
163
|
+
], results: [] },
|
|
164
|
+
{ id: "promo", name: "Promote the website", status: "pending", subtasks: [
|
|
165
|
+
"Share on social media",
|
|
166
|
+
"Submit to directories",
|
|
167
|
+
"Run ad campaigns"
|
|
168
|
+
], results: [] }
|
|
169
|
+
]
|
|
170
|
+
} else {
|
|
171
|
+
plan.steps = [
|
|
172
|
+
{ id: "analyze", name: "Analyze the task", status: "pending", subtasks: [
|
|
173
|
+
"Break down requirements",
|
|
174
|
+
"Identify needed resources",
|
|
175
|
+
"Create execution plan"
|
|
176
|
+
], results: [] },
|
|
177
|
+
{ id: "execute", name: "Execute the plan", status: "pending", subtasks: [
|
|
178
|
+
"Implement step by step",
|
|
179
|
+
"Test at each stage",
|
|
180
|
+
"Handle errors and retry"
|
|
181
|
+
], results: [] },
|
|
182
|
+
{ id: "deliver", name: "Deliver results", status: "pending", subtasks: [
|
|
183
|
+
"Document everything",
|
|
184
|
+
"Create summary report",
|
|
185
|
+
"Generate dashboard"
|
|
186
|
+
], results: [] }
|
|
187
|
+
]
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
this.tasks.queue.push(plan)
|
|
191
|
+
this.state.goal = goal
|
|
192
|
+
this.save()
|
|
193
|
+
logEntry("PLAN_CREATED", goal)
|
|
194
|
+
return plan
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
async executeSubtask(subtask, goal, apiCall) {
|
|
198
|
+
const prompt = `You are an autonomous coding agent. Complete this task: "${subtask}"
|
|
199
|
+
Context: Goal is "${goal}"
|
|
200
|
+
|
|
201
|
+
You MUST return a JSON object with actual executable commands and file contents.
|
|
202
|
+
DO NOT just describe — ACTUALLY PLAN THE EXECUTION.
|
|
203
|
+
|
|
204
|
+
Return this exact JSON structure:
|
|
205
|
+
{
|
|
206
|
+
"action": "what will be done",
|
|
207
|
+
"filesToCreate": [
|
|
208
|
+
{"path": "relative/path/file.ext", "content": "FULL file content with all code"}
|
|
209
|
+
],
|
|
210
|
+
"commandsToRun": [
|
|
211
|
+
"shell command 1",
|
|
212
|
+
"shell command 2"
|
|
213
|
+
],
|
|
214
|
+
"result": "description of what will happen",
|
|
215
|
+
"nextSteps": ["what to do next"]
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
IMPORTANT:
|
|
219
|
+
- filesToCreate must contain REAL, COMPLETE, WORKING code (not placeholders)
|
|
220
|
+
- commandsToRun must be real shell commands (npm init, mkdir, etc.)
|
|
221
|
+
- Return ONLY the JSON, no markdown, no explanations`
|
|
222
|
+
|
|
223
|
+
const response = await apiCall(prompt)
|
|
224
|
+
let parsed
|
|
225
|
+
try {
|
|
226
|
+
// Strip markdown code fences if present
|
|
227
|
+
let clean = response.trim()
|
|
228
|
+
if (clean.startsWith("```")) {
|
|
229
|
+
clean = clean.replace(/^```(?:json)?\n?/, "").replace(/\n?```$/, "")
|
|
230
|
+
}
|
|
231
|
+
parsed = JSON.parse(clean)
|
|
232
|
+
} catch {
|
|
233
|
+
parsed = { action: "completed", result: response, filesToCreate: [], commandsToRun: [] }
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
const created = []
|
|
237
|
+
const executed = []
|
|
238
|
+
|
|
239
|
+
// Create actual files
|
|
240
|
+
if (parsed.filesToCreate && Array.isArray(parsed.filesToCreate)) {
|
|
241
|
+
for (const file of parsed.filesToCreate) {
|
|
242
|
+
if (file.path && file.content) {
|
|
243
|
+
try {
|
|
244
|
+
const fullPath = join(process.cwd(), file.path)
|
|
245
|
+
const dir = dirname(fullPath)
|
|
246
|
+
if (!existsSync(dir)) mkdirSync(dir, { recursive: true })
|
|
247
|
+
writeFileSync(fullPath, file.content, "utf-8")
|
|
248
|
+
created.push(file.path)
|
|
249
|
+
this.memory.projects.push({ file: file.path, created: new Date().toISOString(), goal, subtask })
|
|
250
|
+
logEntry("FILE_CREATED", file.path)
|
|
251
|
+
} catch (err) {
|
|
252
|
+
logEntry("FILE_ERROR", `${file.path}: ${err.message}`)
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// Execute actual commands
|
|
259
|
+
if (parsed.commandsToRun && Array.isArray(parsed.commandsToRun)) {
|
|
260
|
+
for (const cmd of parsed.commandsToRun) {
|
|
261
|
+
try {
|
|
262
|
+
execSync(cmd, { timeout: 30000, stdio: "pipe", shell: true, cwd: process.cwd() })
|
|
263
|
+
executed.push(cmd)
|
|
264
|
+
logEntry("CMD_RUN", cmd)
|
|
265
|
+
} catch (err) {
|
|
266
|
+
logEntry("CMD_FAIL", `${cmd}: ${err.message?.slice(0, 100)}`)
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
logEntry("SUBTASK_DONE", `${subtask}: ${created.length} files, ${executed.length} cmds`)
|
|
272
|
+
this.save()
|
|
273
|
+
return { ...parsed, filesCreated: created, commandsRun: executed }
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
async runIteration(apiCall, onProgress) {
|
|
277
|
+
const plan = this.tasks.queue.find(p => p.status !== "completed" && p.status !== "failed")
|
|
278
|
+
if (!plan) return null
|
|
279
|
+
|
|
280
|
+
plan.status = "running"
|
|
281
|
+
const step = plan.steps.find(s => s.status === "pending")
|
|
282
|
+
if (!step) {
|
|
283
|
+
const hasFailed = plan.steps.some(s => s.status === "failed")
|
|
284
|
+
plan.status = hasFailed ? "failed" : "completed"
|
|
285
|
+
this.save()
|
|
286
|
+
logEntry("PLAN_DONE", `${plan.goal}: ${plan.status}`)
|
|
287
|
+
return { type: "plan_done", plan }
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
step.status = "running"
|
|
291
|
+
this.save()
|
|
292
|
+
if (onProgress) onProgress(`⚡ Executing: ${step.name}`)
|
|
293
|
+
logEntry("STEP_START", step.name)
|
|
294
|
+
|
|
295
|
+
const stepResults = []
|
|
296
|
+
let failed = false
|
|
297
|
+
|
|
298
|
+
for (const subtask of step.subtasks) {
|
|
299
|
+
try {
|
|
300
|
+
if (onProgress) onProgress(` → ${subtask}`)
|
|
301
|
+
const result = await this.executeSubtask(subtask, plan.goal, apiCall)
|
|
302
|
+
stepResults.push(result)
|
|
303
|
+
|
|
304
|
+
// Report created files
|
|
305
|
+
if (result.filesCreated && result.filesCreated.length > 0) {
|
|
306
|
+
for (const f of result.filesCreated) {
|
|
307
|
+
if (onProgress) onProgress(` 📄 Created: ${f}`)
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
if (result.commandsRun && result.commandsRun.length > 0) {
|
|
311
|
+
for (const c of result.commandsRun) {
|
|
312
|
+
if (onProgress) onProgress(` ⚙️ Ran: ${c}`)
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
} catch (err) {
|
|
316
|
+
logEntry("SUBTASK_FAIL", `${subtask}: ${err.message}`)
|
|
317
|
+
stepResults.push({ error: err.message })
|
|
318
|
+
failed = true
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
step.status = failed ? "failed" : "completed"
|
|
323
|
+
step.results = stepResults
|
|
324
|
+
this.save()
|
|
325
|
+
logEntry("STEP_DONE", `${step.name}: ${step.status}`)
|
|
326
|
+
return { type: "step_done", step, plan }
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
async start(goal, apiCall, onProgress) {
|
|
330
|
+
this.state.running = true
|
|
331
|
+
this.state.startedAt = new Date().toISOString()
|
|
332
|
+
this.state.goal = goal
|
|
333
|
+
this.state.iterations = 0
|
|
334
|
+
this.save()
|
|
335
|
+
|
|
336
|
+
const plan = this.planGoal(goal)
|
|
337
|
+
logEntry("AGENT_START", goal)
|
|
338
|
+
|
|
339
|
+
while (this.state.running) {
|
|
340
|
+
this.state.iterations++
|
|
341
|
+
const result = await this.runIteration(apiCall, onProgress)
|
|
342
|
+
|
|
343
|
+
if (!result) {
|
|
344
|
+
this.state.running = false
|
|
345
|
+
this.save()
|
|
346
|
+
logEntry("AGENT_DONE", "All plans completed!")
|
|
347
|
+
if (onProgress) onProgress("ALL_DONE")
|
|
348
|
+
break
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
if (result.type === "plan_done") {
|
|
352
|
+
if (onProgress) onProgress(`Plan completed: ${result.plan.goal}`)
|
|
353
|
+
} else if (result.type === "step_done") {
|
|
354
|
+
if (onProgress) onProgress(`Step done: ${result.step.name}`)
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
await new Promise(r => setTimeout(r, 500))
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
this.state.running = false
|
|
361
|
+
this.save()
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
stop() {
|
|
365
|
+
this.state.running = false
|
|
366
|
+
this.save()
|
|
367
|
+
logEntry("AGENT_STOPPED", "Manually stopped")
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
getStatus() {
|
|
371
|
+
const plan = this.tasks.queue.find(p => p.status === "running" || p.status === "planning")
|
|
372
|
+
return {
|
|
373
|
+
running: this.state.running,
|
|
374
|
+
goal: this.state.goal,
|
|
375
|
+
iterations: this.state.iterations,
|
|
376
|
+
startedAt: this.state.startedAt,
|
|
377
|
+
currentPlan: plan ? {
|
|
378
|
+
goal: plan.goal,
|
|
379
|
+
status: plan.status,
|
|
380
|
+
steps: plan.steps.map(s => ({
|
|
381
|
+
name: s.name,
|
|
382
|
+
status: s.status,
|
|
383
|
+
total: s.subtasks.length,
|
|
384
|
+
done: (s.results || []).filter(r => !r.error).length
|
|
385
|
+
}))
|
|
386
|
+
} : null,
|
|
387
|
+
completedPlans: this.tasks.queue.filter(p => p.status === "completed").length,
|
|
388
|
+
failedPlans: this.tasks.queue.filter(p => p.status === "failed").length,
|
|
389
|
+
totalFiles: this.memory.projects.length,
|
|
390
|
+
totalEarnings: this.memory.earnings,
|
|
391
|
+
accounts: this.memory.accounts.length
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
generateDashboard() {
|
|
396
|
+
const completedPlans = this.tasks.queue.filter(p => p.status === "completed")
|
|
397
|
+
const failedPlans = this.tasks.queue.filter(p => p.status === "failed")
|
|
398
|
+
const activePlans = this.tasks.queue.filter(p => p.status === "running" || p.status === "planning")
|
|
399
|
+
const allFiles = [...new Set(this.memory.projects.map(p => p.file))]
|
|
400
|
+
const logs = existsSync(LOG_FILE) ? readFileSync(LOG_FILE, "utf-8").split("\n").filter(Boolean).slice(-100) : []
|
|
401
|
+
|
|
402
|
+
const html = `<!DOCTYPE html>
|
|
403
|
+
<html lang="ru">
|
|
404
|
+
<head>
|
|
405
|
+
<meta charset="UTF-8">
|
|
406
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
407
|
+
<title>Stella Autonomous Dashboard</title>
|
|
408
|
+
<style>
|
|
409
|
+
*{margin:0;padding:0;box-sizing:border-box}
|
|
410
|
+
body{background:#0a0a0f;color:#f8fafc;font-family:'Courier New',monospace;min-height:100vh}
|
|
411
|
+
.hdr{background:linear-gradient(135deg,#0f0f1a,#1a0a2e);padding:2rem 3rem;border-bottom:2px solid #22c55e;display:flex;justify-content:space-between;align-items:center}
|
|
412
|
+
.hdr h1{font-size:2rem;color:#22c55e}
|
|
413
|
+
.hdr .status{display:flex;align-items:center;gap:8px}
|
|
414
|
+
.hdr .dot{width:12px;height:12px;border-radius:50%;background:${this.state.running ? "#22c55e" : "#ef4444"};animation:pulse 1.5s infinite}
|
|
415
|
+
@keyframes pulse{0%,100%{opacity:1}50%{opacity:.4}}
|
|
416
|
+
.grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:1rem;padding:2rem 3rem}
|
|
417
|
+
.card{background:#111118;border:1px solid #22c55e33;border-radius:12px;padding:1.5rem;text-align:center;transition:border-color .3s}
|
|
418
|
+
.card:hover{border-color:#22c55e}
|
|
419
|
+
.card .num{font-size:2.5rem;color:#22c55e;font-weight:bold}
|
|
420
|
+
.card .lbl{color:#94a3b8;margin-top:.3rem;font-size:.85rem}
|
|
421
|
+
.sec{padding:1.5rem 3rem}
|
|
422
|
+
.sec h2{color:#22c55e;font-size:1.3rem;margin-bottom:1rem;display:flex;align-items:center;gap:8px}
|
|
423
|
+
.plan-card{background:#111118;border:1px solid #333;border-radius:12px;padding:1.5rem;margin-bottom:1rem}
|
|
424
|
+
.plan-card h3{color:#e2e8f0;font-size:1.1rem}
|
|
425
|
+
.plan-card .meta{color:#64748b;font-size:.8rem;margin:.5rem 0}
|
|
426
|
+
.step-row{display:flex;align-items:center;gap:10px;padding:.6rem 0;border-bottom:1px solid #1a1a2e}
|
|
427
|
+
.step-row:last-child{border:none}
|
|
428
|
+
.badge{padding:3px 10px;border-radius:6px;font-size:.7rem;font-weight:bold;text-transform:uppercase}
|
|
429
|
+
.badge.completed{background:#22c55e22;color:#22c55e}
|
|
430
|
+
.badge.failed{background:#ef444422;color:#ef4444}
|
|
431
|
+
.badge.running{background:#eab30822;color:#eab308}
|
|
432
|
+
.badge.pending{background:#64748b22;color:#64748b}
|
|
433
|
+
.badge.planning{background:#3b82f622;color:#3b82f6}
|
|
434
|
+
.files-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:.5rem}
|
|
435
|
+
.file-item{background:#16161f;padding:.5rem 1rem;border-radius:6px;font-size:.85rem;color:#22c55e;display:flex;align-items:center;gap:6px}
|
|
436
|
+
.log-box{background:#111118;border-radius:12px;padding:1rem;max-height:400px;overflow-y:auto;font-size:.78rem;color:#94a3b8;line-height:1.6}
|
|
437
|
+
.log-box div{padding:2px 0;border-bottom:1px solid #111}
|
|
438
|
+
.log-box .ts{color:#64748b}
|
|
439
|
+
.footer{text-align:center;padding:2rem;color:#475569;border-top:1px solid #1a1a2e;margin-top:2rem}
|
|
440
|
+
.empty{text-align:center;padding:3rem;color:#475569;font-size:1.1rem}
|
|
441
|
+
</style>
|
|
442
|
+
</head>
|
|
443
|
+
<body>
|
|
444
|
+
<div class="hdr">
|
|
445
|
+
<div>
|
|
446
|
+
<h1>🤖 Stella Autonomous Agent</h1>
|
|
447
|
+
<p style="color:#94a3b8;margin-top:.3rem">Self-driving coding machine — powered by codex alex</p>
|
|
448
|
+
</div>
|
|
449
|
+
<div class="status">
|
|
450
|
+
<div class="dot"></div>
|
|
451
|
+
<span style="color:${this.state.running ? "#22c55e" : "#ef4444"};font-weight:bold">${this.state.running ? "RUNNING" : "IDLE"}</span>
|
|
452
|
+
</div>
|
|
453
|
+
</div>
|
|
454
|
+
|
|
455
|
+
<div class="grid">
|
|
456
|
+
<div class="card"><div class="num">${completedPlans.length}</div><div class="lbl">Plans Done</div></div>
|
|
457
|
+
<div class="card"><div class="num">${activePlans.length}</div><div class="lbl">Active Plans</div></div>
|
|
458
|
+
<div class="card"><div class="num">${failedPlans.length}</div><div class="lbl">Failed</div></div>
|
|
459
|
+
<div class="card"><div class="num">${allFiles.length}</div><div class="lbl">Files Created</div></div>
|
|
460
|
+
<div class="card"><div class="num">$${this.memory.earnings.toFixed(2)}</div><div class="lbl">Earnings</div></div>
|
|
461
|
+
<div class="card"><div class="num">${this.memory.accounts.length}</div><div class="lbl">Accounts</div></div>
|
|
462
|
+
<div class="card"><div class="num">${this.state.iterations}</div><div class="lbl">Iterations</div></div>
|
|
463
|
+
<div class="card"><div class="num">${this.memory.videos.length}</div><div class="lbl">Videos</div></div>
|
|
464
|
+
</div>
|
|
465
|
+
|
|
466
|
+
${activePlans.length > 0 ? `
|
|
467
|
+
<div class="sec">
|
|
468
|
+
<h2>⚡ Active Plans</h2>
|
|
469
|
+
${activePlans.map(p => `
|
|
470
|
+
<div class="plan-card">
|
|
471
|
+
<h3>${p.goal}</h3>
|
|
472
|
+
<div class="meta">Started: ${new Date(p.createdAt).toLocaleString()}</div>
|
|
473
|
+
${p.steps.map(s => `
|
|
474
|
+
<div class="step-row">
|
|
475
|
+
<span class="badge ${s.status}">${s.status}</span>
|
|
476
|
+
<span>${s.name}</span>
|
|
477
|
+
<span style="margin-left:auto;color:#64748b">${(s.results||[]).filter(r=>!r.error).length}/${s.subtasks.length}</span>
|
|
478
|
+
</div>
|
|
479
|
+
`).join("")}
|
|
480
|
+
</div>
|
|
481
|
+
`).join("")}
|
|
482
|
+
</div>` : ""}
|
|
483
|
+
|
|
484
|
+
${completedPlans.length > 0 ? `
|
|
485
|
+
<div class="sec">
|
|
486
|
+
<h2>✅ Completed Plans</h2>
|
|
487
|
+
${completedPlans.map(p => `
|
|
488
|
+
<div class="plan-card">
|
|
489
|
+
<h3>${p.goal}</h3>
|
|
490
|
+
<div class="meta">Completed: ${new Date(p.createdAt).toLocaleString()}</div>
|
|
491
|
+
${p.steps.map(s => `
|
|
492
|
+
<div class="step-row">
|
|
493
|
+
<span class="badge completed">done</span>
|
|
494
|
+
<span>${s.name}</span>
|
|
495
|
+
</div>
|
|
496
|
+
`).join("")}
|
|
497
|
+
</div>
|
|
498
|
+
`).join("")}
|
|
499
|
+
</div>` : ""}
|
|
500
|
+
|
|
501
|
+
${failedPlans.length > 0 ? `
|
|
502
|
+
<div class="sec">
|
|
503
|
+
<h2>❌ Failed Plans</h2>
|
|
504
|
+
${failedPlans.map(p => `
|
|
505
|
+
<div class="plan-card">
|
|
506
|
+
<h3>${p.goal}</h3>
|
|
507
|
+
${p.steps.filter(s=>s.status==="failed").map(s => `
|
|
508
|
+
<div class="step-row">
|
|
509
|
+
<span class="badge failed">failed</span>
|
|
510
|
+
<span>${s.name}</span>
|
|
511
|
+
</div>
|
|
512
|
+
`).join("")}
|
|
513
|
+
</div>
|
|
514
|
+
`).join("")}
|
|
515
|
+
</div>` : ""}
|
|
516
|
+
|
|
517
|
+
<div class="sec">
|
|
518
|
+
<h2>📁 All Created Files</h2>
|
|
519
|
+
${allFiles.length > 0 ? `
|
|
520
|
+
<div class="files-grid">
|
|
521
|
+
${allFiles.map(f => `<div class="file-item">📄 ${f}</div>`).join("")}
|
|
522
|
+
</div>
|
|
523
|
+
` : '<div class="empty">No files created yet</div>'}
|
|
524
|
+
</div>
|
|
525
|
+
|
|
526
|
+
<div class="sec">
|
|
527
|
+
<h2>📝 Activity Log (last 100 entries)</h2>
|
|
528
|
+
<div class="log-box">
|
|
529
|
+
${logs.length > 0 ? logs.map(l => {
|
|
530
|
+
const parts = l.match(/\[(.*?)\] (\w+): (.*)/)
|
|
531
|
+
if (parts) return `<div><span class="ts">${parts[1]}</span> <span style="color:#22c55e">${parts[2]}</span> ${parts[3]}</div>`
|
|
532
|
+
return `<div>${l}</div>`
|
|
533
|
+
}).join("") : '<div>No activity yet</div>'}
|
|
534
|
+
</div>
|
|
535
|
+
</div>
|
|
536
|
+
|
|
537
|
+
<div class="footer">
|
|
538
|
+
<p>Stella Coder 5.1 — Autonomous Agent Dashboard</p>
|
|
539
|
+
<p>Generated: ${new Date().toLocaleString()} · Goal: ${this.state.goal || "None"}</p>
|
|
540
|
+
</div>
|
|
541
|
+
</body>
|
|
542
|
+
</html>`
|
|
543
|
+
|
|
544
|
+
ensureDir()
|
|
545
|
+
writeFileSync(DASHBOARD_FILE, html)
|
|
546
|
+
return DASHBOARD_FILE
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
export default AutonomousAgent
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { gradient, dim, violet, blue, gray, box, bold, purple } from "./theme.mjs"
|
|
2
|
+
|
|
3
|
+
const LOGO = String.raw`
|
|
4
|
+
███████╗████████╗███████╗██╗ ██╗ █████╗
|
|
5
|
+
██╔════╝╚══██╔══╝██╔════╝██║ ██║ ██╔══██╗
|
|
6
|
+
███████╗ ██║ █████╗ ██║ ██║ ███████║
|
|
7
|
+
╚════██║ ██║ ██╔══╝ ██║ ██║ ██╔══██║
|
|
8
|
+
███████║ ██║ ███████╗███████╗███████╗██║ ██║
|
|
9
|
+
╚══════╝ ╚═╝ ╚══════╝╚══════╝╚══════╝╚═╝ ╚═╝
|
|
10
|
+
██████╗ ██████╗ ██████╗ ███████╗██████╗
|
|
11
|
+
██╔════╝██╔═══██╗██╔══██╗██╔════╝██╔══██╗
|
|
12
|
+
██║ ██║ ██║██║ ██║█████╗ ██████╔╝
|
|
13
|
+
██║ ██║ ██║██║ ██║██╔══╝ ██╔══██╗
|
|
14
|
+
╚██████╗╚██████╔╝██████╔╝███████╗██║ ██║
|
|
15
|
+
╚═════╝ ╚═════╝ ╚═════╝ ╚══════╝╚═╝ ╚═╝`
|
|
16
|
+
|
|
17
|
+
export function printBanner({ model, cwd, version }) {
|
|
18
|
+
console.log(gradient(LOGO))
|
|
19
|
+
console.log()
|
|
20
|
+
console.log(
|
|
21
|
+
" " +
|
|
22
|
+
gradient("✦ Stella Coder") +
|
|
23
|
+
" " +
|
|
24
|
+
bold(violet(`v${version}`)) +
|
|
25
|
+
dim(" · powered by ") +
|
|
26
|
+
bold(blue("codex")) +
|
|
27
|
+
dim(" alex"),
|
|
28
|
+
)
|
|
29
|
+
console.log()
|
|
30
|
+
console.log(
|
|
31
|
+
box(
|
|
32
|
+
[
|
|
33
|
+
violet("✻") + " Добро пожаловать в " + bold(violet("Stella Coder 5.1")) + "!",
|
|
34
|
+
"",
|
|
35
|
+
dim(" модель: ") + blue(model),
|
|
36
|
+
dim(" папка: ") + gray(cwd),
|
|
37
|
+
"",
|
|
38
|
+
dim(" ") + purple("/help") + dim(" — все команды ") + purple("/model") + dim(" — сменить модель"),
|
|
39
|
+
dim(" ") + purple("!cmd") + dim(" — запустить shell-команду напрямую"),
|
|
40
|
+
dim(" ") + purple("Ctrl+C") + dim(" — прервать ответ, дважды — выход"),
|
|
41
|
+
],
|
|
42
|
+
{ title: "✦ System", padding: 2 },
|
|
43
|
+
),
|
|
44
|
+
)
|
|
45
|
+
console.log()
|
|
46
|
+
}
|