DevOps-agentti: Dockerfile + docker-compose.yml + README pipeline-vaiheina

DevOps generoi nyt kolme tiedostoa:
- Dockerfile (multi-stage build, python:3.12-slim)
- docker-compose.yml (palvelut, volumet, portit)
- README.md (quick start docker compose up)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-07 06:41:34 +03:00
parent f1b57a6c53
commit ac698a766e

View File

@@ -1157,7 +1157,7 @@
coder: { name: 'Koodari — System Prompt', model: 'qwen-coder', default: 'Olet kokenut ohjelmistokehittäjä. Kirjoita selkeää, testattavaa koodia ja vastaa aina koodilla.' }, coder: { name: 'Koodari — System Prompt', model: 'qwen-coder', default: 'Olet kokenut ohjelmistokehittäjä. Kirjoita selkeää, testattavaa koodia ja vastaa aina koodilla.' },
data: { name: 'Data-Agentti — System Prompt', model: 'qwen-coder', default: 'Olet tietokanta-asiantuntija. Vastaat skeemojen suunnittelusta, SQL-kyselyiden optimoinnista ja datamalleista.' }, data: { name: 'Data-Agentti — System Prompt', model: 'qwen-coder', default: 'Olet tietokanta-asiantuntija. Vastaat skeemojen suunnittelusta, SQL-kyselyiden optimoinnista ja datamalleista.' },
qa: { name: 'QA — System Prompt', model: 'qwen-coder', default: 'Olet laadunvarmistaja (QA). Kirjoitat testejä, etsit virheitä ja varmistat, että kaikki reunatapaukset on huomioitu.' }, qa: { name: 'QA — System Prompt', model: 'qwen-coder', default: 'Olet laadunvarmistaja (QA). Kirjoitat testejä, etsit virheitä ja varmistat, että kaikki reunatapaukset on huomioitu.' },
tester: { name: 'DevOps — System Prompt', model: 'qwen-coder', default: 'Olet DevOps-insinööri. Vastaat koodin julkaisuputkista, serveri-infrastruktuurista ja ympäristön suorituskyvystä.' }, tester: { name: 'DevOps — System Prompt', model: 'qwen-coder', default: 'Olet DevOps-insinööri. Kirjoitat Dockerfile- ja docker-compose.yml-tiedostot, README:t ja käynnistysohjeet. Käytä aina multi-stage Docker buildia ja docker compose -orkestrointia.' },
}; };
const selectedAgents = new Set(); const selectedAgents = new Set();
let sharedPrompt = localStorage.getItem('kpn-shared-prompt') || ''; let sharedPrompt = localStorage.getItem('kpn-shared-prompt') || '';
@@ -2208,21 +2208,53 @@ ${Object.entries(generatedFiles).map(([n, c]) => `--- ${n} ---\n${c}`).join('\n\
if (tests) generatedFiles['test_app.py'] = tests; if (tests) generatedFiles['test_app.py'] = tests;
pipelineStep('qa', 'Testit', 'done', 'test_app.py', tests); pipelineStep('qa', 'Testit', 'done', 'test_app.py', tests);
// Vaihe 6: DevOps — käynnistysohjeet // Vaihe 6: DevOps — Dockerfile
const step6 = step5 + 1; const step6 = step5 + 1;
termLog(`\n<span style="color:#d29922;font-weight:bold">[${step6}] DevOps</span> — käynnistys`); termLog(`\n<span style="color:#d29922;font-weight:bold">[${step6}] DevOps</span> — Dockerfile`);
pipelineStep('tester', 'DevOps', 'active', 'Käynnistysohjeet'); pipelineStep('tester', 'Dockerfile', 'active', 'Dockerfile');
const devopsPrompt = `Write a minimal README.md for this project. Include ONLY: const dockerPrompt = `Write a Dockerfile for this project. Use multi-stage build:
1. One-line description - Stage 1 (builder): install dependencies
2. How to install (pip/uv) - Stage 2 (runtime): copy only what's needed, minimal image
3. How to run Use python:3.12-slim as base. EXPOSE the correct port. CMD to start the app.
4. How to test Only output the Dockerfile content, nothing else.
Max 15 lines. No badges, no license, no contributing section.
Files: ${Object.keys(generatedFiles).join(', ')}
Main app entry: ${Object.keys(generatedFiles).find(f => f.includes('main') || f.includes('app')) || Object.keys(generatedFiles)[0]}`;
const dockerfile = await kpnRun(agentPrompts.tester.model, dockerPrompt, false, 256);
if (dockerfile) generatedFiles['Dockerfile'] = dockerfile;
pipelineStep('tester', 'Dockerfile', 'done', 'Dockerfile', dockerfile);
// Vaihe 7: DevOps — docker-compose.yml
const step7 = step6 + 1;
termLog(`\n<span style="color:#d29922;font-weight:bold">[${step7}] DevOps</span> — docker-compose.yml`);
pipelineStep('tester', 'Compose', 'active', 'docker-compose.yml');
const composePrompt = `Write a docker-compose.yml for this project. Include:
- app service (build from Dockerfile, port mapping, restart: unless-stopped)
- db service if SQLite/PostgreSQL is used (volume for data persistence)
- Named volumes for persistent data
Only output the YAML content, nothing else.
Files: ${Object.keys(generatedFiles).join(', ')}`; Files: ${Object.keys(generatedFiles).join(', ')}`;
const readme = await kpnRun(agentPrompts.tester.model, devopsPrompt, false, 256); const compose = await kpnRun(agentPrompts.tester.model, composePrompt, false, 256);
if (compose) generatedFiles['docker-compose.yml'] = compose;
pipelineStep('tester', 'Compose', 'done', 'docker-compose.yml', compose);
// Vaihe 8: DevOps — README
const step8 = step7 + 1;
termLog(`\n<span style="color:#d29922;font-weight:bold">[${step8}] DevOps</span> — README`);
pipelineStep('tester', 'README', 'active', 'README.md');
const readmePrompt = `Write a minimal README.md. Include ONLY:
1. One-line description
2. Quick start: docker compose up
3. Development: how to run without Docker
4. API endpoints (if applicable)
5. How to test
Max 20 lines.
Files: ${Object.keys(generatedFiles).join(', ')}`;
const readme = await kpnRun(agentPrompts.tester.model, readmePrompt, false, 256);
if (readme) generatedFiles['README.md'] = readme; if (readme) generatedFiles['README.md'] = readme;
pipelineStep('tester', 'DevOps', 'done', 'README.md', readme); pipelineStep('tester', 'README', 'done', 'README.md', readme);
termLog(`\n<span style="color:#a371f7;font-weight:bold">━━━ Pipeline valmis (${Object.keys(generatedFiles).length} tiedostoa) ━━━</span>`); termLog(`\n<span style="color:#a371f7;font-weight:bold">━━━ Pipeline valmis (${Object.keys(generatedFiles).length} tiedostoa) ━━━</span>`);
renderProjectCard(generatedFiles, task); renderProjectCard(generatedFiles, task);