start-vibing-stacks 2.31.0 → 2.32.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 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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "start-vibing-stacks",
3
- "version": "2.31.0",
3
+ "version": "2.32.0",
4
4
  "description": "AI-powered multi-stack dev workflow for Claude Code. Supports PHP, Node.js, Python and more.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -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: secrets-management
3
- version: 2.0.0
3
+ version: 2.1.0
4
4
  description: "Environment variable hygiene, OIDC federation for CI/CD (2026 default — replaces long-lived static secrets), secret detection (gitleaks 3-layer: pre-commit + CI + GitHub push protection), rotation, and secret-store patterns. Invoke whenever .env, secrets, API keys, env-var-reading code, or CI cloud-deploy credentials are touched."
5
5
  ---
6
6
 
@@ -59,6 +59,81 @@ OPENAI_API_KEY=sk-...
59
59
 
60
60
  ---
61
61
 
62
+ ## `.env.d/` Directory Pattern (Multi-Work / Multi-Session)
63
+
64
+ For projects with multiple worktrees, parallel Claude sessions, or complex environment matrices, use the `.env.d/` directory pattern instead of a single `.env` file.
65
+
66
+ ### Recommended Layout
67
+ ```
68
+ .env.d/
69
+ local/
70
+ 01-app.env
71
+ 10-db.env
72
+ 20-auth.env
73
+ 30-third-party.env
74
+ staging/
75
+ 01-app.env
76
+ ...
77
+ production/
78
+ 01-app.env
79
+ ...
80
+ shared/
81
+ 99-common.env
82
+ ```
83
+
84
+ ### Rules
85
+ - **Load order:** Files are sourced alphabetically (`01-` before `10-` before `99-`).
86
+ - **Session isolation:** Each Claude session should only touch files inside its own worktree's `.env.d/local/`.
87
+ - **Never commit real secrets:** Only commit `.env.d/*/ *.example` or `.env.d/*/.gitkeep`.
88
+ - **JSON / PEM / SSH keys:** Place in `.env.d/local/secrets/` (gitignored) and reference via absolute path in the `.env` files.
89
+
90
+ ```bash
91
+ # .env.d/local/30-secrets.env
92
+ PRIVATE_KEY_PATH=/absolute/path/to/.env.d/local/secrets/service-account.json
93
+ SSH_KEY_PATH=/absolute/path/to/.env.d/local/secrets/id_ed25519
94
+ ```
95
+
96
+ ### `.gitignore` for `.env.d/`
97
+ ```gitignore
98
+ .env.d/
99
+ !**/.gitkeep
100
+ !**/*.example
101
+ ```
102
+
103
+ ---
104
+
105
+ ## Secret Files (JSON, PEM, SSH Keys) — Multi-Session Safe Handling
106
+
107
+ When a secret must live in a file (service account JSON, SSH private key, certificate bundle, etc.):
108
+
109
+ 1. **Store in `.env.d/<env>/secrets/`** (never in repo root or `src/`).
110
+ 2. **Reference by absolute path** in the corresponding `.env.d/<env>/*.env` file.
111
+ 3. **Never read the file content into a variable** unless you immediately redact it from logs/memory.
112
+ 4. **Claude sessions must never cross worktree boundaries** — the `pre-tool-use.ts` hook already enforces this via `filesTouched` tracking.
113
+
114
+ ### Example (Node.js)
115
+ ```ts
116
+ import { readFileSync } from 'fs';
117
+
118
+ const serviceAccount = JSON.parse(
119
+ readFileSync(process.env['GOOGLE_APPLICATION_CREDENTIALS']!, 'utf8')
120
+ );
121
+ ```
122
+
123
+ ### Example (Python)
124
+ ```python
125
+ from pathlib import Path
126
+ import json
127
+
128
+ key_path = Path(os.environ["PRIVATE_KEY_PATH"])
129
+ service_account = json.loads(key_path.read_text())
130
+ ```
131
+
132
+ ### Multi-Session Coordination Note
133
+ The coordination layer (`_state.ts`, `pre-tool-use.ts`, `stop-validator.ts`) treats `.env.d/` files the same as any other file. If two sessions attempt to edit the same secret file within 5 minutes, the second session is blocked. This is intentional — secrets must be edited serially.
134
+
135
+ ---
136
+
62
137
  ## Reading Env Vars Safely
63
138
 
64
139
  ### Node.js / TypeScript
@@ -329,3 +404,16 @@ Lockfile rules:
329
404
  - `observability` — log redaction details
330
405
  - `ci-pipelines` — OIDC patterns + workflow permissions
331
406
  - Stack `api-security-*` — usage patterns
407
+ - `memory-optimization` — when this skill grows beyond ~200 lines, run MOP to keep it actionable
408
+
409
+ ## Memory Optimization Trigger
410
+
411
+ If this skill accumulates:
412
+ - 3+ duplicate rotation playbooks across stacks
413
+ - 5+ generic "rotate after leak" paragraphs
414
+ - Repeated OIDC examples that differ only by cloud provider
415
+
416
+ → Suggest running:
417
+ ```bash
418
+ npx start-vibing-stacks memory optimize --dry-run
419
+ ```