start-vibing-stacks 2.31.0 → 2.33.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/dist/index.js +4 -0
- package/dist/setup.d.ts +1 -0
- package/dist/setup.js +7 -0
- package/package.json +1 -1
- package/stacks/_shared/ads-agents/references/memory-optimization-rules.md +29 -0
- package/stacks/_shared/memories/memory-optimization.md +54 -0
- package/stacks/_shared/memory-optimization/chunker.ts +53 -0
- package/stacks/_shared/memory-optimization/config.default.json +29 -0
- package/stacks/_shared/memory-optimization/evolutionary.ts +14 -0
- package/stacks/_shared/memory-optimization/judge.ts +101 -0
- package/stacks/_shared/memory-optimization/merger.ts +17 -0
- package/stacks/_shared/memory-optimization/pipeline.ts +70 -0
- package/stacks/_shared/memory-optimization/templates/optimized.md.hbs +12 -0
- package/stacks/_shared/memory-optimization/templates/report.md.hbs +33 -0
- package/stacks/_shared/skills/docker-patterns/SKILL.md +12 -2
- package/stacks/_shared/skills/kubernetes-patterns/SKILL.md +312 -0
- package/stacks/_shared/skills/laravel-octane-inertia/SKILL.md +213 -0
- package/stacks/_shared/skills/podman-patterns/SKILL.md +260 -0
- package/stacks/_shared/skills/react-server-components/SKILL.md +194 -0
- package/stacks/_shared/skills/secrets-management/SKILL.md +89 -1
- package/stacks/nodejs/stack.json +5 -2
- package/stacks/php/stack.json +7 -3
- package/stacks/python/stack.json +3 -1
package/dist/index.js
CHANGED
|
@@ -34,6 +34,7 @@ const FLAGS = {
|
|
|
34
34
|
version: args.includes('--version') || args.includes('-v'),
|
|
35
35
|
apply: args.includes('--apply'),
|
|
36
36
|
forceHooks: args.includes('--force-hooks') || args.includes('--force-legacy'),
|
|
37
|
+
withMemoryOptimization: args.includes('--with-memory-optimization'),
|
|
37
38
|
};
|
|
38
39
|
if (FLAGS.version) {
|
|
39
40
|
console.log(PKG_VERSION);
|
|
@@ -59,6 +60,8 @@ if (FLAGS.help) {
|
|
|
59
60
|
--no-claude Skip Claude Code installation
|
|
60
61
|
--no-mcp Skip MCP server selection
|
|
61
62
|
--no-install Skip dependency installation
|
|
63
|
+
--with-memory-optimization
|
|
64
|
+
Install the Memory Optimization Pipeline (MOP) for static memory maintenance
|
|
62
65
|
--help, -h Show this help
|
|
63
66
|
--version, -v Show version
|
|
64
67
|
|
|
@@ -350,6 +353,7 @@ async function main() {
|
|
|
350
353
|
const setupOk = await setupProject(projectDir, config, {
|
|
351
354
|
force: FLAGS.force,
|
|
352
355
|
noClaude: FLAGS.noClaude,
|
|
356
|
+
withMemoryOptimization: FLAGS.withMemoryOptimization,
|
|
353
357
|
});
|
|
354
358
|
if (!setupOk) {
|
|
355
359
|
ui.error('Setup failed.');
|
package/dist/setup.d.ts
CHANGED
|
@@ -14,4 +14,5 @@ export declare function loadStackConfig(stackId: string): StackConfig | null;
|
|
|
14
14
|
export declare function setupProject(projectDir: string, config: ProjectConfig, options?: {
|
|
15
15
|
force?: boolean;
|
|
16
16
|
noClaude?: boolean;
|
|
17
|
+
withMemoryOptimization?: boolean;
|
|
17
18
|
}): Promise<boolean>;
|
package/dist/setup.js
CHANGED
|
@@ -231,6 +231,13 @@ export async function setupProject(projectDir, config, options = {}) {
|
|
|
231
231
|
if (existsSync(sharedMemoriesDir)) {
|
|
232
232
|
copyDirRecursive(sharedMemoriesDir, join(claudeDir, 'memories'), options.force);
|
|
233
233
|
}
|
|
234
|
+
// 12c. Copy Memory Optimization Pipeline (MOP) if flag is present
|
|
235
|
+
if (options.withMemoryOptimization) {
|
|
236
|
+
const sharedMopDir = join(PACKAGE_ROOT, 'stacks', '_shared', 'memory-optimization');
|
|
237
|
+
if (existsSync(sharedMopDir)) {
|
|
238
|
+
copyDirRecursive(sharedMopDir, join(claudeDir, 'memory-optimization'), options.force);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
234
241
|
// 13. Write settings.json for Claude Code (complete config)
|
|
235
242
|
const settings = {
|
|
236
243
|
model: 'sonnet',
|
package/package.json
CHANGED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Memory Optimization Pipeline Rules
|
|
2
|
+
|
|
3
|
+
> **Status:** Auto-loaded memory via `memory-optimization.md`.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## When to Suggest MOP
|
|
8
|
+
|
|
9
|
+
The agent should suggest running the Memory Optimization Pipeline when any of the following objective signals are detected:
|
|
10
|
+
|
|
11
|
+
- 3 or more redundant chunks across different memory files
|
|
12
|
+
- 5 or more generic chunks (low specificity)
|
|
13
|
+
- `CLAUDE.md` exceeding 35,000 characters
|
|
14
|
+
- A static memory not updated for more than 30 days
|
|
15
|
+
- Repeated "forgetting" of decisions or patterns during a session
|
|
16
|
+
|
|
17
|
+
## How to Suggest
|
|
18
|
+
|
|
19
|
+
Always suggest, never execute automatically:
|
|
20
|
+
|
|
21
|
+
> "I detected X redundant/generic chunks in the memories. I recommend running:
|
|
22
|
+
> `npx start-vibing-stacks memory optimize --dry-run`"
|
|
23
|
+
|
|
24
|
+
## Safety Rules
|
|
25
|
+
|
|
26
|
+
- Never propose modifying original `.md` files directly.
|
|
27
|
+
- Always recommend reviewing the generated report first.
|
|
28
|
+
- GEPA mode should only be suggested for very large or long-lived projects.
|
|
29
|
+
- The MOP is a maintenance tool, not an autonomous agent.
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Memory: Memory Optimization Pipeline (MOP)
|
|
2
|
+
|
|
3
|
+
> **CARREGAR SEMPRE** — Esta memória explica o sistema de otimização de memórias estáticas do projeto. O agente deve entender que o MOP é uma ferramenta de manutenção segura, versionável e não intrusiva.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## O que é o MOP
|
|
8
|
+
|
|
9
|
+
O Memory Optimization Pipeline (MOP) é uma ferramenta que avalia, densifica e evolui as memórias estáticas do projeto (`.claude/memories/*.md`) usando **LLM-as-Judge** e, opcionalmente, técnicas evolutivas (GEPA).
|
|
10
|
+
|
|
11
|
+
**Princípio fundamental:** O MOP **nunca modifica** os arquivos originais. Ele sempre gera versões otimizadas (`.optimized.md`) e relatórios de mudanças para revisão humana.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Regras de Ouro do MOP
|
|
16
|
+
|
|
17
|
+
1. **Nunca modificar** arquivos `.md` originais
|
|
18
|
+
2. **Nunca modificar** `CLAUDE.md`
|
|
19
|
+
3. **Nunca modificar** Skills (`SKILL.md`)
|
|
20
|
+
4. **Nunca adicionar** hooks automáticos no `settings.json`
|
|
21
|
+
5. **Nunca rodar** automaticamente sem confirmação explícita do usuário
|
|
22
|
+
6. **Sempre gerar** relatório explicativo antes de qualquer mudança
|
|
23
|
+
7. **Sempre ser** idempotente e reversível
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Quando o MOP Deve Ser Invocado
|
|
28
|
+
|
|
29
|
+
O agente deve sugerir o uso do MOP quando detectar:
|
|
30
|
+
|
|
31
|
+
- 3 ou mais chunks redundantes entre memórias diferentes
|
|
32
|
+
- 5 ou mais chunks genéricos (pouca especificidade)
|
|
33
|
+
- `CLAUDE.md` com mais de 35.000 caracteres
|
|
34
|
+
- Memória estática não atualizada há mais de 30 dias
|
|
35
|
+
- Sinais de degradação de qualidade de memória (perda de decisões, padrões ou gotchas)
|
|
36
|
+
|
|
37
|
+
**Nunca execute o MOP automaticamente.** Sempre sugira ou peça confirmação explícita (`npx start-vibing-stacks memory optimize --apply`).
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## Integração com o Agente
|
|
42
|
+
|
|
43
|
+
Quando o usuário pedir para otimizar memórias, o agente deve:
|
|
44
|
+
|
|
45
|
+
1. Executar o pipeline em modo dry-run primeiro
|
|
46
|
+
2. Apresentar o relatório gerado
|
|
47
|
+
3. Só aplicar mudanças após confirmação explícita
|
|
48
|
+
4. Nunca sobrescrever memórias originais sem criar backup explícito
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## Lembrete para o Modelo
|
|
53
|
+
|
|
54
|
+
O MOP existe para combater a **degradação progressiva** de memórias estáticas em projetos longos. Ele é uma ferramenta de **manutenção**, não um processo autônomo. Respeite rigorosamente as regras de não intrusão.
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { randomUUID } from 'crypto';
|
|
2
|
+
|
|
3
|
+
export interface MemoryChunk {
|
|
4
|
+
id: string;
|
|
5
|
+
text: string;
|
|
6
|
+
sourceFile: string;
|
|
7
|
+
startLine?: number;
|
|
8
|
+
endLine?: number;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Semantic chunker (placeholder).
|
|
13
|
+
* In a real implementation, this would use LLM to split memories into
|
|
14
|
+
* semantically coherent chunks instead of naive line-based splitting.
|
|
15
|
+
*/
|
|
16
|
+
export function chunkMemory(content: string, sourceFile: string): MemoryChunk[] {
|
|
17
|
+
const lines = content.split('\n');
|
|
18
|
+
const chunks: MemoryChunk[] = [];
|
|
19
|
+
let currentChunk: string[] = [];
|
|
20
|
+
let startLine = 1;
|
|
21
|
+
|
|
22
|
+
for (let i = 0; i < lines.length; i++) {
|
|
23
|
+
const line = lines[i];
|
|
24
|
+
currentChunk.push(line);
|
|
25
|
+
|
|
26
|
+
// Naive heuristic: split on double newlines or section headers
|
|
27
|
+
if (line.trim() === '' || line.startsWith('##')) {
|
|
28
|
+
if (currentChunk.length > 3) {
|
|
29
|
+
chunks.push({
|
|
30
|
+
id: randomUUID(),
|
|
31
|
+
text: currentChunk.join('\n').trim(),
|
|
32
|
+
sourceFile,
|
|
33
|
+
startLine,
|
|
34
|
+
endLine: i + 1
|
|
35
|
+
});
|
|
36
|
+
currentChunk = [];
|
|
37
|
+
startLine = i + 2;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (currentChunk.length > 3) {
|
|
43
|
+
chunks.push({
|
|
44
|
+
id: randomUUID(),
|
|
45
|
+
text: currentChunk.join('\n').trim(),
|
|
46
|
+
sourceFile,
|
|
47
|
+
startLine,
|
|
48
|
+
endLine: lines.length
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return chunks;
|
|
53
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"model": "sonnet",
|
|
3
|
+
"temperature": 0.3,
|
|
4
|
+
"maxTokensPerCall": 4000,
|
|
5
|
+
"criteria": {
|
|
6
|
+
"relevance": 0.30,
|
|
7
|
+
"specificity": 0.25,
|
|
8
|
+
"actionability": 0.20,
|
|
9
|
+
"uniqueness": 0.15,
|
|
10
|
+
"freshness": 0.10
|
|
11
|
+
},
|
|
12
|
+
"thresholds": {
|
|
13
|
+
"minScore": 0.60,
|
|
14
|
+
"mergeThreshold": 0.85,
|
|
15
|
+
"archiveThreshold": 0.40
|
|
16
|
+
},
|
|
17
|
+
"evolutionary": {
|
|
18
|
+
"enabled": false,
|
|
19
|
+
"generations": 5,
|
|
20
|
+
"populationSize": 20,
|
|
21
|
+
"elitismRate": 0.20,
|
|
22
|
+
"crossoverRate": 0.60,
|
|
23
|
+
"mutationRate": 0.20
|
|
24
|
+
},
|
|
25
|
+
"limits": {
|
|
26
|
+
"maxChunksPerMemory": 200,
|
|
27
|
+
"maxReportLength": 3000
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Evolutionary (GEPA) layer (stub).
|
|
3
|
+
*
|
|
4
|
+
* This file exists for future expansion.
|
|
5
|
+
* GEPA is disabled by default in config.json.
|
|
6
|
+
* When enabled, this module would implement:
|
|
7
|
+
* - Population management
|
|
8
|
+
* - Crossover / Mutation operators
|
|
9
|
+
* - Fitness selection over generations
|
|
10
|
+
*/
|
|
11
|
+
export function runGEPA(chunks: any[], config: any): any[] {
|
|
12
|
+
console.log('[GEPA] Evolutionary optimization is disabled by default.');
|
|
13
|
+
return chunks;
|
|
14
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { readFileSync } from 'fs';
|
|
2
|
+
import { join } from 'path';
|
|
3
|
+
|
|
4
|
+
export interface ChunkEvaluation {
|
|
5
|
+
chunkId: string;
|
|
6
|
+
text: string;
|
|
7
|
+
scores: {
|
|
8
|
+
relevance: number;
|
|
9
|
+
specificity: number;
|
|
10
|
+
actionability: number;
|
|
11
|
+
uniqueness: number;
|
|
12
|
+
freshness: number;
|
|
13
|
+
};
|
|
14
|
+
finalScore: number;
|
|
15
|
+
recommendation: 'keep' | 'merge' | 'archive' | 'rewrite';
|
|
16
|
+
reason: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface JudgeConfig {
|
|
20
|
+
model: string;
|
|
21
|
+
temperature: number;
|
|
22
|
+
criteria: Record<string, number>;
|
|
23
|
+
thresholds: {
|
|
24
|
+
minScore: number;
|
|
25
|
+
mergeThreshold: number;
|
|
26
|
+
archiveThreshold: number;
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const DEFAULT_CRITERIA = {
|
|
31
|
+
relevance: 0.30,
|
|
32
|
+
specificity: 0.25,
|
|
33
|
+
actionability: 0.20,
|
|
34
|
+
uniqueness: 0.15,
|
|
35
|
+
freshness: 0.10
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export async function evaluateChunk(
|
|
39
|
+
chunk: { id: string; text: string },
|
|
40
|
+
config: JudgeConfig,
|
|
41
|
+
context: string
|
|
42
|
+
): Promise<ChunkEvaluation> {
|
|
43
|
+
const prompt = buildJudgePrompt(chunk.text, config.criteria, context);
|
|
44
|
+
|
|
45
|
+
// In a real implementation, this would call the Claude API
|
|
46
|
+
// For now, we return a placeholder structure.
|
|
47
|
+
// The actual LLM call will be implemented when integrating with the pipeline.
|
|
48
|
+
|
|
49
|
+
const mockScores = {
|
|
50
|
+
relevance: 0.85,
|
|
51
|
+
specificity: 0.70,
|
|
52
|
+
actionability: 0.65,
|
|
53
|
+
uniqueness: 0.80,
|
|
54
|
+
freshness: 0.90
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const finalScore = Object.entries(mockScores).reduce((acc, [key, value]) => {
|
|
58
|
+
return acc + value * (config.criteria[key as keyof typeof config.criteria] || 0);
|
|
59
|
+
}, 0);
|
|
60
|
+
|
|
61
|
+
let recommendation: ChunkEvaluation['recommendation'] = 'keep';
|
|
62
|
+
if (finalScore < config.thresholds.archiveThreshold) recommendation = 'archive';
|
|
63
|
+
else if (finalScore < config.thresholds.minScore) recommendation = 'rewrite';
|
|
64
|
+
else if (finalScore > config.thresholds.mergeThreshold) recommendation = 'merge';
|
|
65
|
+
|
|
66
|
+
return {
|
|
67
|
+
chunkId: chunk.id,
|
|
68
|
+
text: chunk.text,
|
|
69
|
+
scores: mockScores,
|
|
70
|
+
finalScore: Math.round(finalScore * 100) / 100,
|
|
71
|
+
recommendation,
|
|
72
|
+
reason: `Score ${finalScore.toFixed(2)} — ${recommendation} based on weighted criteria.`
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function buildJudgePrompt(text: string, criteria: Record<string, number>, context: string): string {
|
|
77
|
+
return `You are an expert memory curator for AI coding agents.
|
|
78
|
+
|
|
79
|
+
Evaluate the following memory chunk according to these weighted criteria:
|
|
80
|
+
|
|
81
|
+
${Object.entries(criteria).map(([k, v]) => `- ${k}: ${v * 100}%`).join('\n')}
|
|
82
|
+
|
|
83
|
+
Context about the project:
|
|
84
|
+
${context}
|
|
85
|
+
|
|
86
|
+
Chunk to evaluate:
|
|
87
|
+
"""
|
|
88
|
+
${text}
|
|
89
|
+
"""
|
|
90
|
+
|
|
91
|
+
Respond ONLY with a valid JSON object:
|
|
92
|
+
{
|
|
93
|
+
"relevance": 0.0-1.0,
|
|
94
|
+
"specificity": 0.0-1.0,
|
|
95
|
+
"actionability": 0.0-1.0,
|
|
96
|
+
"uniqueness": 0.0-1.0,
|
|
97
|
+
"freshness": 0.0-1.0,
|
|
98
|
+
"recommendation": "keep" | "merge" | "archive" | "rewrite",
|
|
99
|
+
"reason": "one sentence justification"
|
|
100
|
+
}`;
|
|
101
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { MemoryChunk } from './chunker.js';
|
|
2
|
+
|
|
3
|
+
export interface MergeSuggestion {
|
|
4
|
+
sourceChunks: string[];
|
|
5
|
+
mergedText: string;
|
|
6
|
+
reason: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Merger (placeholder).
|
|
11
|
+
* In a real implementation, this would use LLM to intelligently merge
|
|
12
|
+
* related chunks while preserving specificity and actionability.
|
|
13
|
+
*/
|
|
14
|
+
export function suggestMerges(chunks: MemoryChunk[]): MergeSuggestion[] {
|
|
15
|
+
// Placeholder: In real version, call LLM to find merge candidates
|
|
16
|
+
return [];
|
|
17
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Memory Optimization Pipeline (MOP)
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
* npx tsx .claude/memory-optimization/pipeline.ts optimize --dry-run
|
|
7
|
+
* npx tsx .claude/memory-optimization/pipeline.ts optimize --apply
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'fs';
|
|
11
|
+
import { join, dirname } from 'path';
|
|
12
|
+
import { evaluateChunk, type JudgeConfig } from './judge.js';
|
|
13
|
+
|
|
14
|
+
const PROJECT_DIR = process.env.CLAUDE_PROJECT_DIR || process.cwd();
|
|
15
|
+
const MEMORIES_DIR = join(PROJECT_DIR, '.claude', 'memories');
|
|
16
|
+
const MOP_DIR = join(PROJECT_DIR, '.claude', 'memory-optimization');
|
|
17
|
+
const CONFIG_PATH = join(MOP_DIR, 'config.json');
|
|
18
|
+
|
|
19
|
+
interface PipelineOptions {
|
|
20
|
+
dryRun: boolean;
|
|
21
|
+
apply: boolean;
|
|
22
|
+
gepa: boolean;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function loadConfig(): JudgeConfig {
|
|
26
|
+
if (existsSync(CONFIG_PATH)) {
|
|
27
|
+
return JSON.parse(readFileSync(CONFIG_PATH, 'utf8'));
|
|
28
|
+
}
|
|
29
|
+
// Fallback to default
|
|
30
|
+
return JSON.parse(
|
|
31
|
+
readFileSync(join(dirname(import.meta.url), 'config.default.json'), 'utf8')
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async function main() {
|
|
36
|
+
const args = process.argv.slice(2);
|
|
37
|
+
const command = args[0];
|
|
38
|
+
|
|
39
|
+
if (command !== 'optimize') {
|
|
40
|
+
console.log('Usage: pipeline.ts optimize [--dry-run] [--apply] [--gepa]');
|
|
41
|
+
process.exit(1);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const options: PipelineOptions = {
|
|
45
|
+
dryRun: args.includes('--dry-run'),
|
|
46
|
+
apply: args.includes('--apply'),
|
|
47
|
+
gepa: args.includes('--gepa')
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const config = loadConfig();
|
|
51
|
+
|
|
52
|
+
console.log('Memory Optimization Pipeline');
|
|
53
|
+
console.log(`Mode: ${options.dryRun ? 'DRY-RUN' : options.apply ? 'APPLY' : 'REPORT'}`);
|
|
54
|
+
console.log(`GEPA: ${options.gepa ? 'ENABLED' : 'DISABLED'}`);
|
|
55
|
+
|
|
56
|
+
// Placeholder for actual logic
|
|
57
|
+
// 1. Load memories
|
|
58
|
+
// 2. Chunk
|
|
59
|
+
// 3. Judge
|
|
60
|
+
// 4. (Optional) GEPA
|
|
61
|
+
// 5. Generate report + optimized files
|
|
62
|
+
|
|
63
|
+
console.log('\n[INFO] Pipeline skeleton executed. Full implementation pending.');
|
|
64
|
+
console.log('This is a safe dry-run placeholder. No files were modified.');
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
main().catch(err => {
|
|
68
|
+
console.error('Pipeline failed:', err);
|
|
69
|
+
process.exit(1);
|
|
70
|
+
});
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# {{memoryName}} (Optimized)
|
|
2
|
+
|
|
3
|
+
> **This is an optimized version generated by MOP.**
|
|
4
|
+
> Original file: `{{originalFile}}`
|
|
5
|
+
> Generated on: {{date}}
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
{{optimizedContent}}
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
*End of optimized memory. Review before replacing the original.*
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Memory Optimization Report
|
|
2
|
+
|
|
3
|
+
**Generated:** {{date}}
|
|
4
|
+
**Mode:** {{mode}}
|
|
5
|
+
**Memories analyzed:** {{memoryCount}}
|
|
6
|
+
|
|
7
|
+
## Summary
|
|
8
|
+
|
|
9
|
+
- Total chunks evaluated: {{totalChunks}}
|
|
10
|
+
- Recommended to keep: {{keepCount}}
|
|
11
|
+
- Recommended to merge: {{mergeCount}}
|
|
12
|
+
- Recommended to archive: {{archiveCount}}
|
|
13
|
+
- Recommended to rewrite: {{rewriteCount}}
|
|
14
|
+
|
|
15
|
+
## Detailed Findings
|
|
16
|
+
|
|
17
|
+
{{#each findings}}
|
|
18
|
+
### {{sourceFile}}
|
|
19
|
+
|
|
20
|
+
- **Recommendation:** {{recommendation}}
|
|
21
|
+
- **Score:** {{score}}
|
|
22
|
+
- **Reason:** {{reason}}
|
|
23
|
+
|
|
24
|
+
{{/each}}
|
|
25
|
+
|
|
26
|
+
## Recommended Actions
|
|
27
|
+
|
|
28
|
+
1. Review the generated `.optimized.md` files.
|
|
29
|
+
2. Run with `--apply` only after manual review.
|
|
30
|
+
3. Commit the `.optimized.md` files for traceability.
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
*This report was generated by the Memory Optimization Pipeline (MOP). No original files were modified.*
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: docker-patterns
|
|
3
|
-
version: 2.
|
|
3
|
+
version: 2.1.0
|
|
4
4
|
description: "Docker patterns for 2026: BuildKit + Buildx Bake (default builder for Docker Compose since June 2025), multi-stage builds, distroless / chiseled bases (90% size reduction, no shell), non-root users, .dockerignore, healthchecks, additional_contexts for service deps, secrets via build mounts (not COPY), reproducible builds. Stack examples: Node 22, Python 3.13 (uv), PHP 8.4 (FPM + Nginx)."
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -86,7 +86,16 @@ RUN apk add --no-cache libzip-dev oniguruma-dev icu-dev \
|
|
|
86
86
|
&& rm -rf /var/cache/apk/*
|
|
87
87
|
WORKDIR /var/www/html
|
|
88
88
|
COPY --from=vendor /app/vendor ./vendor
|
|
89
|
-
|
|
89
|
+
# Only copy what the runtime actually needs (never .env, tests, .git, node_modules, etc.)
|
|
90
|
+
COPY --chown=www-data:www-data artisan composer.json composer.lock ./
|
|
91
|
+
COPY --chown=www-data:www-data app/ ./app/
|
|
92
|
+
COPY --chown=www-data:www-data bootstrap/ ./bootstrap/
|
|
93
|
+
COPY --chown=www-data:www-data config/ ./config/
|
|
94
|
+
COPY --chown=www-data:www-data database/ ./database/
|
|
95
|
+
COPY --chown=www-data:www-data public/ ./public/
|
|
96
|
+
COPY --chown=www-data:www-data resources/ ./resources/
|
|
97
|
+
COPY --chown=www-data:www-data routes/ ./routes/
|
|
98
|
+
COPY --chown=www-data:www-data storage/ ./storage/
|
|
90
99
|
USER www-data
|
|
91
100
|
EXPOSE 9000
|
|
92
101
|
HEALTHCHECK --interval=30s --timeout=3s CMD php-fpm-healthcheck || exit 1
|
|
@@ -203,3 +212,4 @@ For Kubernetes the Dockerfile HEALTHCHECK is informational only — the cluster
|
|
|
203
212
|
- `security-baseline` (2025-A03) — supply chain: pin actions by SHA, sign images (Sigstore/cosign)
|
|
204
213
|
- `observability` — `/healthz` + `/readyz` semantics
|
|
205
214
|
- `ci-pipelines` — building & pushing in CI
|
|
215
|
+
- `podman-patterns` — rootless execution, Quadlet, `podman play kube`, and daemonless alternative (same Dockerfiles work)
|