universal-agent-memory 0.1.1 → 0.1.3
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/bin/cli.js +8 -1
- package/dist/bin/cli.js.map +1 -1
- package/dist/generators/claude-md.d.ts.map +1 -1
- package/dist/generators/claude-md.js +612 -536
- package/dist/generators/claude-md.js.map +1 -1
- package/package.json +1 -1
- package/templates/CLAUDE.template.md +157 -211
|
@@ -1,641 +1,717 @@
|
|
|
1
1
|
import Handlebars from 'handlebars';
|
|
2
|
+
import { existsSync, readFileSync, readdirSync, statSync } from 'fs';
|
|
3
|
+
import { join } from 'path';
|
|
4
|
+
import { prepopulateMemory } from '../memory/prepopulate.js';
|
|
2
5
|
export async function generateClaudeMd(analysis, config) {
|
|
3
|
-
|
|
6
|
+
// Determine platform mode
|
|
7
|
+
const hasWebDatabase = !!config.memory?.shortTerm?.webDatabase;
|
|
8
|
+
const forceDesktop = config.memory?.shortTerm?.forceDesktop;
|
|
9
|
+
const isWebPlatform = hasWebDatabase && !forceDesktop;
|
|
10
|
+
// Use appropriate template
|
|
11
|
+
const template = isWebPlatform ? getWebTemplate() : getDesktopTemplate();
|
|
4
12
|
const compiled = Handlebars.compile(template);
|
|
5
|
-
|
|
13
|
+
// Build comprehensive context from analysis + auto-population
|
|
14
|
+
const context = await buildContext(analysis, config);
|
|
6
15
|
return compiled(context);
|
|
7
16
|
}
|
|
8
|
-
function buildContext(analysis, config) {
|
|
9
|
-
|
|
17
|
+
async function buildContext(analysis, config) {
|
|
18
|
+
const cwd = process.cwd();
|
|
19
|
+
// Detect web vs desktop
|
|
10
20
|
const hasWebDatabase = !!config.memory?.shortTerm?.webDatabase;
|
|
11
21
|
const forceDesktop = config.memory?.shortTerm?.forceDesktop;
|
|
12
22
|
const isWebPlatform = hasWebDatabase && !forceDesktop;
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
let longTermProvider = 'qdrant';
|
|
23
|
+
// Long-term memory config
|
|
24
|
+
let longTermBackend = 'Qdrant';
|
|
16
25
|
let longTermEndpoint = config.memory?.longTerm?.endpoint || 'localhost:6333';
|
|
17
|
-
|
|
26
|
+
const longTermCollection = config.memory?.longTerm?.collection || 'agent_memory';
|
|
18
27
|
if (config.memory?.longTerm?.provider === 'github') {
|
|
19
|
-
|
|
28
|
+
longTermBackend = 'GitHub';
|
|
20
29
|
longTermEndpoint = `${config.memory?.longTerm?.github?.repo || 'owner/repo'}/${config.memory?.longTerm?.github?.path || '.uam/memory'}`;
|
|
21
30
|
}
|
|
22
31
|
else if (config.memory?.longTerm?.provider === 'qdrant-cloud') {
|
|
23
|
-
|
|
32
|
+
longTermBackend = 'Qdrant Cloud';
|
|
24
33
|
longTermEndpoint = config.memory?.longTerm?.qdrantCloud?.url || 'https://xxxxxx.aws.cloud.qdrant.io:6333';
|
|
25
34
|
}
|
|
26
|
-
//
|
|
27
|
-
|
|
28
|
-
|
|
35
|
+
// Prepopulate memory from project
|
|
36
|
+
let prepopulated = null;
|
|
37
|
+
try {
|
|
38
|
+
prepopulated = await prepopulateMemory(cwd, { docs: true, git: true, skills: true, limit: 200 });
|
|
39
|
+
}
|
|
40
|
+
catch (e) {
|
|
41
|
+
console.warn('Failed to prepopulate memory:', e);
|
|
42
|
+
}
|
|
43
|
+
// Build repository structure
|
|
44
|
+
const repoStructure = buildRepositoryStructure(cwd, analysis);
|
|
45
|
+
// Discover skills, droids, commands
|
|
46
|
+
const discoveredSkills = prepopulated?.skills || [];
|
|
47
|
+
const skills = discoveredSkills.filter(s => s.type === 'skill');
|
|
48
|
+
const droids = discoveredSkills.filter(s => s.type === 'droid');
|
|
49
|
+
// Commands discovered from prepopulate (unused currently but kept for reference)
|
|
50
|
+
// const commands = discoveredSkills.filter(s => s.type === 'command');
|
|
51
|
+
// Build skill mappings table
|
|
52
|
+
const skillMappings = buildSkillMappings(skills);
|
|
53
|
+
// Build language droids table
|
|
54
|
+
const languageDroids = buildLanguageDroidsTable(droids, analysis.languages);
|
|
55
|
+
// Build discovered skills table
|
|
56
|
+
const discoveredSkillsTable = buildDiscoveredSkillsTable(skills);
|
|
57
|
+
// Extract troubleshooting from git history
|
|
58
|
+
const troubleshooting = buildTroubleshootingSection(prepopulated?.longTerm || []);
|
|
59
|
+
// Build architecture overview
|
|
60
|
+
const architectureOverview = buildArchitectureOverview(analysis);
|
|
61
|
+
// Build core components section
|
|
62
|
+
const coreComponents = buildCoreComponentsSection(analysis);
|
|
63
|
+
// Build key config files
|
|
64
|
+
const keyConfigFiles = buildKeyConfigFiles(analysis);
|
|
65
|
+
// Build essential commands
|
|
66
|
+
const essentialCommands = buildEssentialCommands(analysis);
|
|
67
|
+
// Build prepopulated knowledge section
|
|
68
|
+
const prepopulatedKnowledge = buildPrepopulatedKnowledge(prepopulated);
|
|
69
|
+
// Build cluster contexts
|
|
70
|
+
const clusterContexts = buildClusterContexts(analysis);
|
|
71
|
+
// Build project URLs
|
|
72
|
+
const projectUrls = buildProjectUrls(analysis);
|
|
73
|
+
// Build key workflows
|
|
74
|
+
const keyWorkflows = buildKeyWorkflows(analysis);
|
|
75
|
+
// Build infrastructure workflow
|
|
76
|
+
const infraWorkflow = buildInfraWorkflow(analysis);
|
|
77
|
+
// Build MCP plugins
|
|
78
|
+
const mcpPlugins = buildMcpPlugins(cwd);
|
|
79
|
+
// Build primary skills for decision loop
|
|
80
|
+
const primarySkills = buildPrimarySkills(skills);
|
|
81
|
+
// Build language examples
|
|
82
|
+
const languageExamples = buildLanguageExamples(analysis.languages);
|
|
29
83
|
return {
|
|
84
|
+
// Project basics
|
|
30
85
|
PROJECT_NAME: analysis.projectName || config.project.name,
|
|
31
86
|
DESCRIPTION: analysis.description || config.project.description || '',
|
|
32
87
|
DEFAULT_BRANCH: analysis.defaultBranch || config.project.defaultBranch || 'main',
|
|
33
|
-
// Platform detection
|
|
34
|
-
IS_WEB_PLATFORM: isWebPlatform,
|
|
35
|
-
IS_DESKTOP_PLATFORM: isDesktopPlatform,
|
|
36
88
|
// Issue tracker
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
// Memory config
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
89
|
+
ISSUE_TRACKER: analysis.issueTracker ?
|
|
90
|
+
`Use [${analysis.issueTracker.name}](${analysis.issueTracker.url || '#'}) for issue tracking.` :
|
|
91
|
+
null,
|
|
92
|
+
// Memory config
|
|
93
|
+
MEMORY_DB_PATH: config.memory?.shortTerm?.path || 'agents/data/memory/short_term.db',
|
|
94
|
+
MEMORY_QUERY_CMD: 'uam memory query',
|
|
95
|
+
MEMORY_STORE_CMD: 'uam memory store',
|
|
96
|
+
MEMORY_START_CMD: 'uam memory start',
|
|
97
|
+
MEMORY_STATUS_CMD: 'uam memory status',
|
|
98
|
+
MEMORY_STOP_CMD: 'uam memory stop',
|
|
99
|
+
SHORT_TERM_LIMIT: config.memory?.shortTerm?.maxEntries || 50,
|
|
100
|
+
LONG_TERM_BACKEND: longTermBackend,
|
|
44
101
|
LONG_TERM_ENDPOINT: longTermEndpoint,
|
|
45
102
|
LONG_TERM_COLLECTION: longTermCollection,
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
// Worktree config
|
|
103
|
+
SCREENSHOTS_PATH: 'agents/data/screenshots',
|
|
104
|
+
DOCKER_COMPOSE_PATH: existsSync(join(cwd, 'agents/docker-compose.yml')) ? 'agents/docker-compose.yml' :
|
|
105
|
+
existsSync(join(cwd, 'docker-compose.yml')) ? 'docker-compose.yml' : null,
|
|
106
|
+
// Worktree config
|
|
50
107
|
WORKTREE_DIR: config.worktrees?.directory || '.worktrees',
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
108
|
+
WORKTREE_CREATE_CMD: 'uam worktree create',
|
|
109
|
+
WORKTREE_PR_CMD: 'uam worktree pr',
|
|
110
|
+
WORKTREE_CLEANUP_CMD: 'uam worktree cleanup',
|
|
111
|
+
WORKTREE_APPLIES_TO: 'Application code, configs, workflows, documentation, CLAUDE.md itself',
|
|
112
|
+
BRANCH_PREFIX: config.worktrees?.branchPrefix || 'feature/',
|
|
113
|
+
// Paths
|
|
114
|
+
SKILLS_PATH: '.factory/skills/',
|
|
115
|
+
DROIDS_PATH: '.factory/droids/',
|
|
116
|
+
COMMANDS_PATH: '.factory/commands/',
|
|
117
|
+
DOCS_PATH: analysis.directories.docs[0] || 'docs',
|
|
118
|
+
FIXES_PATH: existsSync(join(cwd, 'docs/fixes')) ? 'docs/fixes/' : null,
|
|
119
|
+
CHANGELOG_PATH: existsSync(join(cwd, 'docs/changelog')) ? 'docs/changelog' : null,
|
|
120
|
+
CHANGELOG_TEMPLATE: existsSync(join(cwd, 'docs/changelog/CHANGELOG_TEMPLATE.md')) ? 'docs/changelog/CHANGELOG_TEMPLATE.md' : null,
|
|
121
|
+
WORKFLOW_DOCS_PATH: existsSync(join(cwd, 'docs/workflows/GIT_WORKTREE_WORKFLOW.md')) ? 'docs/workflows/GIT_WORKTREE_WORKFLOW.md' : null,
|
|
61
122
|
// Commands
|
|
62
123
|
TEST_COMMAND: analysis.commands.test || 'npm test',
|
|
63
124
|
LINT_COMMAND: analysis.commands.lint || 'npm run lint',
|
|
64
125
|
BUILD_COMMAND: analysis.commands.build || 'npm run build',
|
|
126
|
+
HOOKS_INSTALL_CMD: existsSync(join(cwd, '.factory/scripts/install-hooks.sh')) ? '.factory/scripts/install-hooks.sh' : null,
|
|
127
|
+
// Skills and droids
|
|
128
|
+
PRIMARY_SKILLS: primarySkills,
|
|
129
|
+
SKILL_MAPPINGS: skillMappings,
|
|
130
|
+
DISCOVERED_SKILLS: discoveredSkillsTable,
|
|
131
|
+
LANGUAGE_DROIDS: languageDroids,
|
|
132
|
+
LANGUAGE_EXAMPLES: languageExamples,
|
|
133
|
+
// Repository structure
|
|
134
|
+
'@REPOSITORY_STRUCTURE': repoStructure,
|
|
135
|
+
STRUCTURE_DATE: new Date().toLocaleString('en-US', { month: 'long', year: 'numeric' }),
|
|
136
|
+
// Path migrations (if detected from git history)
|
|
137
|
+
PATH_MIGRATIONS: null, // TODO: detect from git mv history
|
|
138
|
+
// Clusters and URLs
|
|
139
|
+
CLUSTER_CONTEXTS: clusterContexts,
|
|
140
|
+
PROJECT_URLS: projectUrls,
|
|
141
|
+
KEY_WORKFLOWS: keyWorkflows,
|
|
142
|
+
ESSENTIAL_COMMANDS: essentialCommands,
|
|
143
|
+
// Architecture
|
|
144
|
+
ARCHITECTURE_OVERVIEW: architectureOverview,
|
|
145
|
+
DATABASE_ARCHITECTURE: analysis.databases.length > 0 ? buildDatabaseArchitecture(analysis) : null,
|
|
146
|
+
// Core components
|
|
147
|
+
CORE_COMPONENTS: coreComponents,
|
|
148
|
+
// Auth flow
|
|
149
|
+
AUTH_FLOW: analysis.authentication ? buildAuthFlow(analysis) : null,
|
|
150
|
+
// Gateway knowledge
|
|
151
|
+
GATEWAY_KNOWLEDGE: null, // Project-specific, detected from k8s/istio files
|
|
152
|
+
// Multi-environment
|
|
153
|
+
MULTI_ENV_CONFIG: null, // Project-specific
|
|
65
154
|
// Infrastructure
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
// Databases
|
|
70
|
-
DATABASES: analysis.databases,
|
|
71
|
-
HAS_DATABASES: analysis.databases.length > 0,
|
|
72
|
-
// Auth
|
|
73
|
-
HAS_AUTH: !!analysis.authentication,
|
|
74
|
-
AUTH_PROVIDER: analysis.authentication?.provider,
|
|
75
|
-
AUTH_DESCRIPTION: analysis.authentication?.description,
|
|
76
|
-
// CI/CD
|
|
77
|
-
HAS_CICD: !!analysis.ciCd,
|
|
78
|
-
CICD_PLATFORM: analysis.ciCd?.platform,
|
|
79
|
-
WORKFLOWS: analysis.ciCd?.workflows || [],
|
|
80
|
-
// Existing agents
|
|
81
|
-
DROIDS: analysis.existingDroids,
|
|
82
|
-
HAS_DROIDS: analysis.existingDroids.length > 0,
|
|
83
|
-
SKILLS: analysis.existingSkills,
|
|
84
|
-
HAS_SKILLS: analysis.existingSkills.length > 0,
|
|
85
|
-
COMMANDS: analysis.existingCommands,
|
|
86
|
-
HAS_COMMANDS: analysis.existingCommands.length > 0,
|
|
155
|
+
HAS_INFRA: analysis.directories.infrastructure.length > 0,
|
|
156
|
+
INFRA_WORKFLOW: infraWorkflow,
|
|
157
|
+
CLUSTER_IDENTIFY: analysis.clusters?.enabled ? 'Identify which cluster(s) affected' : null,
|
|
87
158
|
// Troubleshooting
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
//
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
159
|
+
TROUBLESHOOTING: troubleshooting,
|
|
160
|
+
// Key config files
|
|
161
|
+
KEY_CONFIG_FILES: keyConfigFiles,
|
|
162
|
+
// MCP plugins
|
|
163
|
+
MCP_PLUGINS: mcpPlugins,
|
|
164
|
+
// Prepopulated knowledge
|
|
165
|
+
PREPOPULATED_KNOWLEDGE: prepopulatedKnowledge ? true : null,
|
|
166
|
+
RECENT_ACTIVITY: prepopulatedKnowledge?.recentActivity || null,
|
|
167
|
+
LEARNED_LESSONS: prepopulatedKnowledge?.learnedLessons || null,
|
|
168
|
+
KNOWN_GOTCHAS: prepopulatedKnowledge?.knownGotchas || null,
|
|
169
|
+
HOT_SPOTS: prepopulatedKnowledge?.hotSpots || null,
|
|
170
|
+
// Platform detection
|
|
171
|
+
IS_WEB_PLATFORM: isWebPlatform,
|
|
172
|
+
IS_DESKTOP_PLATFORM: !isWebPlatform,
|
|
99
173
|
};
|
|
100
174
|
}
|
|
101
|
-
function
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
{
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
{
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
{
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
{
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
\`\`\`bash
|
|
161
|
-
# Store learnings after: fixes, discoveries, architecture decisions, gotchas
|
|
162
|
-
uam memory store lesson "What you learned" --tags tag1,tag2 --importance 7
|
|
163
|
-
\`\`\`
|
|
164
|
-
|
|
165
|
-
**Must store memories for:**
|
|
166
|
-
- Infrastructure changes (cost savings, scaling decisions, fixes)
|
|
167
|
-
- Bug fixes and their root causes
|
|
168
|
-
- Architecture decisions and rationale
|
|
169
|
-
- Gotchas and workarounds discovered
|
|
170
|
-
- Performance optimizations
|
|
171
|
-
|
|
172
|
-
### 3. TODO LIST REQUIREMENT
|
|
173
|
-
|
|
174
|
-
- Create todo list for multi-step tasks (3+ steps)
|
|
175
|
-
- Update status IMMEDIATELY after completing each item
|
|
176
|
-
- Never let todos go stale (update every 5-10 tool calls)
|
|
177
|
-
|
|
178
|
-
### 4. VERIFICATION BEFORE COMPLETION
|
|
179
|
-
|
|
180
|
-
- [ ] Used {{#if IS_DESKTOP_PLATFORM}}worktree{{else}}feature branch{{/if}} for code changes? (or explain why not applicable)
|
|
181
|
-
- [ ] Stored significant learnings in memory?
|
|
182
|
-
- [ ] Updated/completed todo list?
|
|
183
|
-
- [ ] Created PR instead of direct commit?
|
|
184
|
-
|
|
185
|
-
---
|
|
186
|
-
|
|
187
|
-
## MEMORY SYSTEM
|
|
188
|
-
|
|
189
|
-
> **CRITICAL**: Memory updates are MANDATORY, not optional. Every significant discovery, fix, or lesson learned MUST be stored before completing a task.
|
|
190
|
-
|
|
191
|
-
{{#if IS_DESKTOP_PLATFORM}}
|
|
192
|
-
### Short-term Memory (SQLite: \`{{SHORT_TERM_PATH}}\`)
|
|
193
|
-
|
|
194
|
-
Table: \`memories\`
|
|
195
|
-
- \`id\`: INTEGER PRIMARY KEY
|
|
196
|
-
- \`timestamp\`: TEXT (ISO8601)
|
|
197
|
-
- \`type\`: TEXT (action|observation|thought|goal)
|
|
198
|
-
- \`content\`: TEXT
|
|
199
|
-
|
|
200
|
-
**BEFORE EACH DECISION**: Query recent entries (last {{SHORT_TERM_MAX_ENTRIES}}) to understand context:
|
|
201
|
-
\`\`\`sql
|
|
202
|
-
SELECT * FROM memories ORDER BY id DESC LIMIT {{SHORT_TERM_MAX_ENTRIES}};
|
|
203
|
-
\`\`\`
|
|
204
|
-
|
|
205
|
-
**AFTER EACH ACTION**: Record what you did and the outcome:
|
|
206
|
-
\`\`\`sql
|
|
207
|
-
INSERT INTO memories (timestamp, type, content) VALUES (datetime('now'), 'action', 'Description...');
|
|
208
|
-
\`\`\`
|
|
209
|
-
|
|
210
|
-
### Long-term Memory ({{LONG_TERM_PROVIDER}}: \`{{LONG_TERM_ENDPOINT}}\`, collection: \`{{LONG_TERM_COLLECTION}}\`)
|
|
211
|
-
|
|
212
|
-
**Start services**: \`uam memory start\`
|
|
213
|
-
|
|
214
|
-
Vector schema:
|
|
215
|
-
- \`id\`: UUID
|
|
216
|
-
- \`vector\`: 384-dim embedding (all-MiniLM-L6-v2)
|
|
217
|
-
- \`payload\`: {type, tags[], content, importance (1-10), timestamp}
|
|
218
|
-
|
|
219
|
-
**Query memories** (semantic search):
|
|
220
|
-
\`\`\`bash
|
|
221
|
-
uam memory query "search term"
|
|
222
|
-
\`\`\`
|
|
223
|
-
|
|
224
|
-
**Store new memory** (MANDATORY for significant learnings):
|
|
225
|
-
\`\`\`bash
|
|
226
|
-
uam memory store <type> "content" --tags tag1,tag2 --importance N
|
|
227
|
-
\`\`\`
|
|
228
|
-
|
|
229
|
-
Memory types: \`fact\`, \`lesson\`, \`skill\`, \`discovery\`, \`preference\`
|
|
230
|
-
|
|
231
|
-
### MANDATORY Memory Triggers
|
|
232
|
-
|
|
233
|
-
**ALWAYS store to long-term memory when you:**
|
|
234
|
-
1. Fix a bug or resolve an error (lesson)
|
|
235
|
-
2. Discover how a system/component works (discovery)
|
|
236
|
-
3. Learn a configuration requirement (fact)
|
|
237
|
-
4. Find a successful approach to a problem (skill)
|
|
238
|
-
5. Identify a coding pattern or convention (preference)
|
|
239
|
-
6. Complete infrastructure changes (fact)
|
|
240
|
-
7. Debug authentication/networking issues (lesson)
|
|
241
|
-
|
|
242
|
-
**Memory storage is part of task completion.** A task is NOT complete until learnings are stored.
|
|
243
|
-
|
|
244
|
-
### Agent Services Setup
|
|
245
|
-
|
|
246
|
-
\`\`\`bash
|
|
247
|
-
# Start services (auto-creates collection and migrates memories)
|
|
248
|
-
uam memory start
|
|
249
|
-
|
|
250
|
-
# Check status
|
|
251
|
-
uam memory status
|
|
252
|
-
|
|
253
|
-
# Stop services
|
|
254
|
-
uam memory stop
|
|
255
|
-
\`\`\`
|
|
256
|
-
|
|
257
|
-
{{else}}
|
|
258
|
-
### Short-term Memory (localStorage)
|
|
259
|
-
|
|
260
|
-
You have access to browser localStorage for maintaining context across messages.
|
|
261
|
-
|
|
262
|
-
Key: \`agent_context_{{PROJECT_NAME}}\`
|
|
263
|
-
|
|
264
|
-
Structure:
|
|
265
|
-
\`\`\`json
|
|
266
|
-
{
|
|
267
|
-
"memories": [
|
|
268
|
-
{"timestamp": "ISO8601", "type": "action|observation|thought|goal", "content": "..."}
|
|
269
|
-
],
|
|
270
|
-
"maxEntries": {{SHORT_TERM_MAX_ENTRIES}}
|
|
175
|
+
function buildRepositoryStructure(cwd, analysis) {
|
|
176
|
+
const lines = [];
|
|
177
|
+
const visited = new Set();
|
|
178
|
+
// Standard directories to look for
|
|
179
|
+
const standardDirs = [
|
|
180
|
+
{ path: 'apps', comment: 'Deployable applications' },
|
|
181
|
+
{ path: 'services', comment: 'Backend microservices' },
|
|
182
|
+
{ path: 'packages', comment: 'Shared packages' },
|
|
183
|
+
{ path: 'libs', comment: 'Shared libraries' },
|
|
184
|
+
{ path: 'src', comment: 'Source code' },
|
|
185
|
+
{ path: 'infra', comment: 'Infrastructure as Code' },
|
|
186
|
+
{ path: 'infrastructure', comment: 'Infrastructure as Code' },
|
|
187
|
+
{ path: 'terraform', comment: 'Terraform configurations' },
|
|
188
|
+
{ path: 'k8s', comment: 'Kubernetes manifests' },
|
|
189
|
+
{ path: 'helm', comment: 'Helm charts' },
|
|
190
|
+
{ path: 'tools', comment: 'Development tools' },
|
|
191
|
+
{ path: 'scripts', comment: 'Automation scripts' },
|
|
192
|
+
{ path: 'tests', comment: 'Test suites' },
|
|
193
|
+
{ path: 'test', comment: 'Test suites' },
|
|
194
|
+
{ path: 'docs', comment: 'Documentation' },
|
|
195
|
+
{ path: '.factory', comment: 'Factory AI configuration' },
|
|
196
|
+
{ path: '.github', comment: 'GitHub configuration' },
|
|
197
|
+
{ path: '.gitlab', comment: 'GitLab configuration' },
|
|
198
|
+
];
|
|
199
|
+
for (const { path, comment } of standardDirs) {
|
|
200
|
+
const fullPath = join(cwd, path);
|
|
201
|
+
if (existsSync(fullPath) && statSync(fullPath).isDirectory()) {
|
|
202
|
+
visited.add(path);
|
|
203
|
+
lines.push(`├── ${path}/`.padEnd(35) + `# ${comment}`);
|
|
204
|
+
// List subdirectories
|
|
205
|
+
try {
|
|
206
|
+
const subdirs = readdirSync(fullPath, { withFileTypes: true })
|
|
207
|
+
.filter(d => d.isDirectory() && !d.name.startsWith('.'))
|
|
208
|
+
.slice(0, 8);
|
|
209
|
+
for (let i = 0; i < subdirs.length; i++) {
|
|
210
|
+
const prefix = i === subdirs.length - 1 ? '│ └── ' : '│ ├── ';
|
|
211
|
+
const subComment = getSubdirComment(path, subdirs[i].name, join(fullPath, subdirs[i].name));
|
|
212
|
+
lines.push(`${prefix}${subdirs[i].name}/`.padEnd(35) + (subComment ? `# ${subComment}` : ''));
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
catch {
|
|
216
|
+
// Ignore permission errors
|
|
217
|
+
}
|
|
218
|
+
lines.push('│');
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
// Add component directories from analysis
|
|
222
|
+
for (const comp of analysis.components) {
|
|
223
|
+
const dirPath = comp.path.split('/')[0];
|
|
224
|
+
if (!visited.has(dirPath) && existsSync(join(cwd, dirPath))) {
|
|
225
|
+
visited.add(dirPath);
|
|
226
|
+
lines.push(`├── ${dirPath}/`.padEnd(35) + `# ${comp.description || comp.name}`);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
// Remove trailing separator
|
|
230
|
+
if (lines.length > 0 && lines[lines.length - 1] === '│') {
|
|
231
|
+
lines.pop();
|
|
232
|
+
}
|
|
233
|
+
return lines.join('\n');
|
|
271
234
|
}
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
235
|
+
function getSubdirComment(parentDir, subdir, fullPath) {
|
|
236
|
+
// Check for package.json, README, etc. to get description
|
|
237
|
+
const packageJsonPath = join(fullPath, 'package.json');
|
|
238
|
+
if (existsSync(packageJsonPath)) {
|
|
239
|
+
try {
|
|
240
|
+
const pkg = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
|
|
241
|
+
if (pkg.description)
|
|
242
|
+
return pkg.description.slice(0, 40);
|
|
243
|
+
}
|
|
244
|
+
catch {
|
|
245
|
+
// Ignore
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
// Default comments based on common patterns
|
|
249
|
+
const patterns = {
|
|
250
|
+
apps: {
|
|
251
|
+
api: 'REST API',
|
|
252
|
+
web: 'Web frontend',
|
|
253
|
+
mobile: 'Mobile app',
|
|
254
|
+
admin: 'Admin dashboard',
|
|
255
|
+
cms: 'CMS',
|
|
256
|
+
},
|
|
257
|
+
services: {
|
|
258
|
+
auth: 'Authentication service',
|
|
259
|
+
gateway: 'API Gateway',
|
|
260
|
+
},
|
|
261
|
+
'.factory': {
|
|
262
|
+
droids: 'Custom AI agents',
|
|
263
|
+
skills: 'Reusable skills',
|
|
264
|
+
commands: 'CLI commands',
|
|
265
|
+
scripts: 'Automation scripts',
|
|
266
|
+
},
|
|
267
|
+
'.github': {
|
|
268
|
+
workflows: 'CI/CD pipelines',
|
|
269
|
+
},
|
|
270
|
+
};
|
|
271
|
+
return patterns[parentDir]?.[subdir] || '';
|
|
290
272
|
}
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
273
|
+
function buildSkillMappings(skills) {
|
|
274
|
+
if (skills.length === 0)
|
|
275
|
+
return null;
|
|
276
|
+
const lines = [];
|
|
277
|
+
for (const skill of skills) {
|
|
278
|
+
if (skill.name.includes('design') || skill.name.includes('ui')) {
|
|
279
|
+
lines.push(`| UI/Design work (buttons, modals, colors, layouts) | \`${skill.name}\` |`);
|
|
280
|
+
}
|
|
281
|
+
else if (skill.name.includes('frontend') || skill.name.includes('react')) {
|
|
282
|
+
lines.push(`| React/TypeScript/Frontend | \`${skill.name}\` |`);
|
|
283
|
+
}
|
|
284
|
+
else if (skill.name.includes('backend') || skill.name.includes('api')) {
|
|
285
|
+
lines.push(`| Backend/API development | \`${skill.name}\` |`);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
return lines.length > 0 ? lines.join('\n') : null;
|
|
289
|
+
}
|
|
290
|
+
function buildLanguageDroidsTable(droids, languages) {
|
|
291
|
+
const languageDroids = droids.filter(d => d.name.includes('-pro') ||
|
|
292
|
+
d.name.includes('specialist') ||
|
|
293
|
+
languages.some(l => d.name.toLowerCase().includes(l.toLowerCase())));
|
|
294
|
+
if (languageDroids.length === 0 && languages.length > 0) {
|
|
295
|
+
// Generate suggested droids based on detected languages
|
|
296
|
+
const suggestions = [];
|
|
297
|
+
for (const lang of languages.slice(0, 5)) {
|
|
298
|
+
const langLower = lang.toLowerCase();
|
|
299
|
+
if (langLower.includes('typescript') || langLower.includes('javascript')) {
|
|
300
|
+
suggestions.push('| `javascript-pro` | ES6+, async patterns, Node.js, promises, event loops |');
|
|
301
|
+
}
|
|
302
|
+
else if (langLower.includes('python')) {
|
|
303
|
+
suggestions.push('| `python-pro` | Async/await, decorators, generators, pytest, type hints |');
|
|
304
|
+
}
|
|
305
|
+
else if (langLower.includes('c++') || langLower.includes('cpp')) {
|
|
306
|
+
suggestions.push('| `cpp-pro` | C++20 with RAII, smart pointers, STL, templates, move semantics |');
|
|
307
|
+
}
|
|
308
|
+
else if (langLower.includes('rust')) {
|
|
309
|
+
suggestions.push('| `rust-pro` | Ownership, lifetimes, async, error handling, macros |');
|
|
310
|
+
}
|
|
311
|
+
else if (langLower.includes('go')) {
|
|
312
|
+
suggestions.push('| `go-pro` | Concurrency, channels, interfaces, error handling |');
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
return suggestions.length > 0 ? [...new Set(suggestions)].join('\n') : null;
|
|
316
|
+
}
|
|
317
|
+
return languageDroids.map(d => `| \`${d.name}\` | ${d.description || `${d.platform} language specialist`} |`).join('\n') || null;
|
|
318
|
+
}
|
|
319
|
+
function buildDiscoveredSkillsTable(skills) {
|
|
320
|
+
if (skills.length === 0)
|
|
321
|
+
return null;
|
|
322
|
+
return skills.slice(0, 10).map(s => {
|
|
323
|
+
const purpose = s.description || `${s.platform} skill`;
|
|
324
|
+
const useWhen = s.name.includes('design') ? 'UI/design work' :
|
|
325
|
+
s.name.includes('test') ? 'Testing and QA' :
|
|
326
|
+
s.name.includes('review') ? 'Code review' :
|
|
327
|
+
'Specialized tasks';
|
|
328
|
+
return `| \`${s.name}\` | ${purpose} | ${useWhen} |`;
|
|
329
|
+
}).join('\n');
|
|
330
|
+
}
|
|
331
|
+
function buildTroubleshootingSection(memories) {
|
|
332
|
+
// Extract fix-related memories
|
|
333
|
+
const fixes = memories.filter(m => m.tags?.includes('bug-fix') ||
|
|
334
|
+
m.tags?.includes('revert') ||
|
|
335
|
+
m.content.toLowerCase().includes('fix') ||
|
|
336
|
+
m.content.toLowerCase().includes('resolved')).slice(0, 15);
|
|
337
|
+
if (fixes.length === 0)
|
|
338
|
+
return null;
|
|
339
|
+
const lines = [];
|
|
340
|
+
for (const fix of fixes) {
|
|
341
|
+
// Extract symptom and solution from content
|
|
342
|
+
const content = fix.content;
|
|
343
|
+
let symptom = '';
|
|
344
|
+
let solution = '';
|
|
345
|
+
if (content.includes('Bug fixed:')) {
|
|
346
|
+
symptom = content.replace('Bug fixed:', '').split('.')[0].trim();
|
|
347
|
+
solution = content.split('.').slice(1).join('.').trim() || 'See commit for details';
|
|
348
|
+
}
|
|
349
|
+
else if (content.includes('Failed approach')) {
|
|
350
|
+
symptom = content.split(':')[1]?.split('.')[0]?.trim() || content.slice(0, 50);
|
|
351
|
+
solution = 'Avoid this approach';
|
|
352
|
+
}
|
|
353
|
+
else {
|
|
354
|
+
symptom = content.slice(0, 60) + (content.length > 60 ? '...' : '');
|
|
355
|
+
solution = 'See memory for details';
|
|
356
|
+
}
|
|
357
|
+
if (symptom) {
|
|
358
|
+
lines.push(`| ${symptom} | ${solution.slice(0, 60)} |`);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
if (lines.length === 0)
|
|
362
|
+
return null;
|
|
363
|
+
return `| Symptom | Solution |\n|---------|----------|\n${lines.join('\n')}`;
|
|
364
|
+
}
|
|
365
|
+
function buildArchitectureOverview(analysis) {
|
|
366
|
+
const sections = [];
|
|
367
|
+
// Infrastructure overview
|
|
368
|
+
if (analysis.infrastructure.iac || analysis.infrastructure.containerOrchestration) {
|
|
369
|
+
sections.push('### Infrastructure\n');
|
|
370
|
+
if (analysis.infrastructure.iac) {
|
|
371
|
+
sections.push(`- **IaC**: ${analysis.infrastructure.iac}`);
|
|
372
|
+
}
|
|
373
|
+
if (analysis.infrastructure.containerOrchestration) {
|
|
374
|
+
sections.push(`- **Orchestration**: ${analysis.infrastructure.containerOrchestration}`);
|
|
375
|
+
}
|
|
376
|
+
if (analysis.infrastructure.cloud && analysis.infrastructure.cloud.length > 0) {
|
|
377
|
+
sections.push(`- **Cloud**: ${analysis.infrastructure.cloud.join(', ')}`);
|
|
378
|
+
}
|
|
379
|
+
sections.push('');
|
|
380
|
+
}
|
|
381
|
+
// Component overview
|
|
382
|
+
if (analysis.components.length > 0) {
|
|
383
|
+
sections.push('### Components\n');
|
|
384
|
+
for (const comp of analysis.components.slice(0, 8)) {
|
|
385
|
+
sections.push(`- **${comp.name}** (\`${comp.path}\`): ${comp.description || `${comp.language} ${comp.framework || 'application'}`}`);
|
|
386
|
+
}
|
|
387
|
+
sections.push('');
|
|
388
|
+
}
|
|
389
|
+
return sections.length > 0 ? sections.join('\n') : null;
|
|
390
|
+
}
|
|
391
|
+
function buildCoreComponentsSection(analysis) {
|
|
392
|
+
if (analysis.components.length === 0)
|
|
393
|
+
return null;
|
|
394
|
+
const sections = [];
|
|
395
|
+
for (const comp of analysis.components.slice(0, 6)) {
|
|
396
|
+
sections.push(`### ${comp.name} (\`${comp.path}\`)\n`);
|
|
397
|
+
sections.push(`- **Language**: ${comp.language}`);
|
|
398
|
+
if (comp.framework) {
|
|
399
|
+
sections.push(`- **Framework**: ${comp.framework}`);
|
|
400
|
+
}
|
|
401
|
+
if (comp.description) {
|
|
402
|
+
sections.push(`- ${comp.description}`);
|
|
403
|
+
}
|
|
404
|
+
sections.push('');
|
|
405
|
+
}
|
|
406
|
+
return sections.join('\n');
|
|
407
|
+
}
|
|
408
|
+
function buildDatabaseArchitecture(analysis) {
|
|
409
|
+
const lines = [];
|
|
410
|
+
for (const db of analysis.databases) {
|
|
411
|
+
lines.push(`- **${db.type}**: ${db.purpose || 'Primary database'}`);
|
|
412
|
+
}
|
|
413
|
+
return lines.join('\n');
|
|
414
|
+
}
|
|
415
|
+
function buildAuthFlow(analysis) {
|
|
416
|
+
if (!analysis.authentication)
|
|
417
|
+
return '';
|
|
418
|
+
const sections = [];
|
|
419
|
+
sections.push(`**Provider**: ${analysis.authentication.provider}\n`);
|
|
420
|
+
if (analysis.authentication.description) {
|
|
421
|
+
sections.push(analysis.authentication.description);
|
|
422
|
+
}
|
|
423
|
+
return sections.join('\n');
|
|
424
|
+
}
|
|
425
|
+
function buildKeyConfigFiles(analysis) {
|
|
426
|
+
const files = [];
|
|
427
|
+
// Add key files from analysis
|
|
428
|
+
for (const kf of analysis.keyFiles.slice(0, 15)) {
|
|
429
|
+
files.push({ file: kf.file, purpose: kf.purpose });
|
|
430
|
+
}
|
|
431
|
+
if (files.length === 0)
|
|
432
|
+
return null;
|
|
433
|
+
return files.map(f => `| \`${f.file}\` | ${f.purpose} |`).join('\n');
|
|
434
|
+
}
|
|
435
|
+
function buildEssentialCommands(analysis) {
|
|
436
|
+
const commands = [];
|
|
437
|
+
// Test command
|
|
438
|
+
if (analysis.commands.test && analysis.commands.test !== 'npm test') {
|
|
439
|
+
commands.push(`# Tests\n${analysis.commands.test}`);
|
|
440
|
+
}
|
|
441
|
+
// Lint command
|
|
442
|
+
if (analysis.commands.lint) {
|
|
443
|
+
commands.push(`# Linting\n${analysis.commands.lint}`);
|
|
444
|
+
}
|
|
445
|
+
// Build command
|
|
446
|
+
if (analysis.commands.build) {
|
|
447
|
+
commands.push(`# Build\n${analysis.commands.build}`);
|
|
448
|
+
}
|
|
449
|
+
// Infrastructure command
|
|
450
|
+
if (analysis.infrastructure.iac === 'Terraform') {
|
|
451
|
+
const infraPath = analysis.directories.infrastructure[0] || 'infra/terraform';
|
|
452
|
+
commands.push(`# Terraform\ncd ${infraPath} && terraform plan`);
|
|
453
|
+
}
|
|
454
|
+
return commands.length > 0 ? commands.join('\n\n') : null;
|
|
455
|
+
}
|
|
456
|
+
function buildClusterContexts(analysis) {
|
|
457
|
+
if (!analysis.clusters?.enabled || !analysis.clusters.contexts)
|
|
458
|
+
return null;
|
|
459
|
+
return analysis.clusters.contexts.map(c => `kubectl config use-context ${c.context} # ${c.name} (${c.purpose})`).join('\n');
|
|
460
|
+
}
|
|
461
|
+
function buildProjectUrls(analysis) {
|
|
462
|
+
if (analysis.urls.length === 0)
|
|
463
|
+
return null;
|
|
464
|
+
return analysis.urls.map(u => `- **${u.name}**: ${u.value}`).join('\n');
|
|
465
|
+
}
|
|
466
|
+
function buildKeyWorkflows(analysis) {
|
|
467
|
+
if (!analysis.ciCd?.workflows || analysis.ciCd.workflows.length === 0)
|
|
468
|
+
return null;
|
|
469
|
+
return analysis.ciCd.workflows.slice(0, 10).map(w => `├── ${w.file}`.padEnd(35) + `# ${w.purpose}`).join('\n');
|
|
470
|
+
}
|
|
471
|
+
function buildInfraWorkflow(analysis) {
|
|
472
|
+
if (analysis.directories.infrastructure.length === 0)
|
|
473
|
+
return null;
|
|
474
|
+
const infraPath = analysis.directories.infrastructure[0];
|
|
475
|
+
const planCmd = analysis.infrastructure.iac === 'Terraform' ? 'terraform plan' :
|
|
476
|
+
analysis.infrastructure.iac === 'Pulumi' ? 'pulumi preview' :
|
|
477
|
+
'infrastructure plan';
|
|
478
|
+
return `1. **Create worktree** for infrastructure changes
|
|
479
|
+
2. Update infrastructure in \`${infraPath}/\`
|
|
480
|
+
3. Update CI/CD workflows in \`.github/workflows/\`
|
|
481
|
+
4. Run \`${planCmd}\`
|
|
482
|
+
5. Update secrets via GitHub Actions (not locally)
|
|
483
|
+
6. **Create PR** with automated review`;
|
|
484
|
+
}
|
|
485
|
+
function buildMcpPlugins(cwd) {
|
|
486
|
+
const mcpPath = join(cwd, '.mcp.json');
|
|
487
|
+
if (!existsSync(mcpPath))
|
|
488
|
+
return null;
|
|
489
|
+
try {
|
|
490
|
+
const mcp = JSON.parse(readFileSync(mcpPath, 'utf-8'));
|
|
491
|
+
if (!mcp.mcpServers && !mcp.plugins)
|
|
492
|
+
return null;
|
|
493
|
+
const plugins = mcp.mcpServers || mcp.plugins || {};
|
|
494
|
+
const lines = [];
|
|
495
|
+
for (const [name, config] of Object.entries(plugins)) {
|
|
496
|
+
const desc = config.description ||
|
|
497
|
+
config.purpose ||
|
|
498
|
+
'MCP plugin';
|
|
499
|
+
lines.push(`| \`${name}\` | ${desc} |`);
|
|
500
|
+
}
|
|
501
|
+
return lines.length > 0 ? lines.join('\n') : null;
|
|
502
|
+
}
|
|
503
|
+
catch {
|
|
504
|
+
return null;
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
function buildPrimarySkills(skills) {
|
|
508
|
+
const primary = skills.filter(s => s.name.includes('design') ||
|
|
509
|
+
s.name.includes('frontend') ||
|
|
510
|
+
s.name.includes('ui')).slice(0, 3);
|
|
511
|
+
if (primary.length === 0)
|
|
512
|
+
return null;
|
|
513
|
+
return primary.map(s => `│ ├─ Use ${s.name} for ${s.description || 'specialized work'} │`).join('\n');
|
|
514
|
+
}
|
|
515
|
+
function buildLanguageExamples(languages) {
|
|
516
|
+
const examples = [];
|
|
517
|
+
for (const lang of languages.slice(0, 3)) {
|
|
518
|
+
const langLower = lang.toLowerCase();
|
|
519
|
+
if (langLower.includes('c++') || langLower.includes('cpp')) {
|
|
520
|
+
examples.push(`# For C++ work\nTask(subagent_type: "cpp-pro", prompt: "Refactor X using RAII...")`);
|
|
521
|
+
}
|
|
522
|
+
else if (langLower.includes('python')) {
|
|
523
|
+
examples.push(`# For Python work\nTask(subagent_type: "python-pro", prompt: "Optimize async handlers...")`);
|
|
524
|
+
}
|
|
525
|
+
else if (langLower.includes('rust')) {
|
|
526
|
+
examples.push(`# For Rust work\nTask(subagent_type: "rust-pro", prompt: "Implement with proper lifetimes...")`);
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
return examples.length > 0 ? examples.join('\n\n') : null;
|
|
530
|
+
}
|
|
531
|
+
function buildPrepopulatedKnowledge(prepopulated) {
|
|
532
|
+
if (!prepopulated)
|
|
533
|
+
return null;
|
|
534
|
+
const { shortTerm, longTerm } = prepopulated;
|
|
535
|
+
// Recent activity from short-term
|
|
536
|
+
const recentActivity = shortTerm
|
|
537
|
+
.filter(m => m.type === 'action' || m.type === 'observation')
|
|
538
|
+
.slice(0, 10)
|
|
539
|
+
.map(m => `- ${m.content.slice(0, 100)}${m.content.length > 100 ? '...' : ''}`)
|
|
540
|
+
.join('\n');
|
|
541
|
+
// Learned lessons from long-term
|
|
542
|
+
const learnedLessons = longTerm
|
|
543
|
+
.filter(m => m.tags?.includes('bug-fix') || m.tags?.includes('lesson') || (m.importance && m.importance >= 7))
|
|
544
|
+
.slice(0, 10)
|
|
545
|
+
.map(m => `- **${m.tags?.slice(0, 2).join(', ') || 'General'}**: ${m.content.slice(0, 80)}...`)
|
|
546
|
+
.join('\n');
|
|
547
|
+
// Known gotchas (from reverts and high-importance fixes)
|
|
548
|
+
const knownGotchas = longTerm
|
|
549
|
+
.filter(m => m.tags?.includes('revert') || m.tags?.includes('failed-approach') || m.content.includes('avoid'))
|
|
550
|
+
.slice(0, 5)
|
|
551
|
+
.map(m => `- ⚠️ ${m.content.slice(0, 100)}`)
|
|
552
|
+
.join('\n');
|
|
553
|
+
// Hot spots
|
|
554
|
+
const hotSpotMemory = longTerm.find(m => m.id === 'git-hotspots');
|
|
555
|
+
const hotSpots = hotSpotMemory?.content || 'No hot spots detected yet.';
|
|
556
|
+
if (!recentActivity && !learnedLessons && !knownGotchas) {
|
|
557
|
+
return null;
|
|
558
|
+
}
|
|
559
|
+
return {
|
|
560
|
+
recentActivity: recentActivity || 'No recent activity recorded.',
|
|
561
|
+
learnedLessons: learnedLessons || 'No lessons recorded yet.',
|
|
562
|
+
knownGotchas: knownGotchas || 'No gotchas recorded yet.',
|
|
563
|
+
hotSpots,
|
|
564
|
+
};
|
|
565
|
+
}
|
|
566
|
+
function getDesktopTemplate() {
|
|
567
|
+
// Read from template file if it exists, otherwise use inline
|
|
568
|
+
const templatePath = join(process.cwd(), 'templates/CLAUDE.template.md');
|
|
569
|
+
if (existsSync(templatePath)) {
|
|
570
|
+
return readFileSync(templatePath, 'utf-8');
|
|
571
|
+
}
|
|
572
|
+
// Fallback inline template for desktop
|
|
573
|
+
return `<coding_guidelines>
|
|
296
574
|
|
|
297
|
-
|
|
298
|
-
1. Fix a bug or resolve an error (lesson)
|
|
299
|
-
2. Discover how a system/component works (discovery)
|
|
300
|
-
3. Learn a configuration requirement (fact)
|
|
301
|
-
4. Find a successful approach to a problem (skill)
|
|
302
|
-
5. Identify a coding pattern or convention (preference)
|
|
303
|
-
6. Complete infrastructure changes (fact)
|
|
304
|
-
7. Debug authentication/networking issues (lesson)
|
|
575
|
+
# CLAUDE.md - {{PROJECT_NAME}} Development Guide
|
|
305
576
|
|
|
306
|
-
|
|
577
|
+
You are Autonomous Claude, a self-directed AI agent with full control over this virtual machine. You operate continuously, making your own decisions.
|
|
307
578
|
|
|
308
|
-
|
|
579
|
+
{{#if ISSUE_TRACKER}}
|
|
580
|
+
**Note**: {{{ISSUE_TRACKER}}}
|
|
309
581
|
{{/if}}
|
|
310
582
|
|
|
311
583
|
---
|
|
312
584
|
|
|
313
|
-
|
|
314
|
-
## BROWSER USAGE
|
|
585
|
+
## ⚠️⚠️⚠️ CRITICAL: MANDATORY DECISION LOOP ⚠️⚠️⚠️
|
|
315
586
|
|
|
316
|
-
|
|
587
|
+
**FOLLOW THIS FOR EVERY ACTION. NO EXCEPTIONS.**
|
|
317
588
|
|
|
318
|
-
|
|
319
|
-
-
|
|
320
|
-
-
|
|
589
|
+
1. **READ MEMORY FIRST**
|
|
590
|
+
- Query short-term: \`sqlite3 {{MEMORY_DB_PATH}} "SELECT * FROM memories ORDER BY id DESC LIMIT 20;"\`
|
|
591
|
+
- Query long-term: \`{{MEMORY_QUERY_CMD}} "<keywords>"\`
|
|
321
592
|
|
|
322
|
-
|
|
593
|
+
2. **CHECK SKILLS** before implementing (see \`{{SKILLS_PATH}}\`)
|
|
323
594
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
1. **READ** short-term memory (recent context)
|
|
328
|
-
2. **QUERY** long-term memory (semantic search for relevant learnings)
|
|
329
|
-
3. **THINK** about what to do next
|
|
330
|
-
4. **ACT** - execute your decision
|
|
331
|
-
5. **RECORD** - write to short-term memory
|
|
332
|
-
6. **STORE** - add significant learnings to long-term memory (MANDATORY, not optional)
|
|
333
|
-
{{#if IS_DESKTOP_PLATFORM}}
|
|
334
|
-
7. **IF BROWSER ACTION**: Save screenshot to \`/agents/data/screenshots/\`
|
|
335
|
-
{{/if}}
|
|
595
|
+
3. **CREATE WORKTREE** for ANY code changes
|
|
596
|
+
- \`{{WORKTREE_CREATE_CMD}} <slug>\`
|
|
597
|
+
- NEVER commit directly to {{DEFAULT_BRANCH}}
|
|
336
598
|
|
|
337
|
-
**
|
|
338
|
-
-
|
|
339
|
-
- [ ] Long-term memory updated with any lessons/discoveries/facts learned
|
|
340
|
-
- [ ] Tests pass (if code changes)
|
|
341
|
-
- [ ] Documentation updated (if applicable)
|
|
599
|
+
4. **UPDATE MEMORY** after significant actions
|
|
600
|
+
- \`{{MEMORY_STORE_CMD}} lesson "What you learned" --tags tag1,tag2 --importance 7\`
|
|
342
601
|
|
|
343
602
|
---
|
|
344
603
|
|
|
345
|
-
|
|
346
|
-
## SKILLS
|
|
347
|
-
|
|
348
|
-
You have access to reusable skills. Before attempting complex tasks:
|
|
349
|
-
|
|
350
|
-
1. Check if a skill exists for it (see \`.factory/skills/\`)
|
|
351
|
-
2. Follow the skill's patterns - they're tested and reliable
|
|
352
|
-
3. If you discover a better approach, consider creating/updating a skill
|
|
353
|
-
|
|
354
|
-
Available skills are auto-discovered. When you see a SKILL.md, follow its instructions.
|
|
604
|
+
## Memory System
|
|
355
605
|
|
|
356
|
-
{{
|
|
357
|
-
- \`{{
|
|
358
|
-
{{/each}}
|
|
359
|
-
|
|
360
|
-
---
|
|
361
|
-
|
|
362
|
-
{{/if}}
|
|
363
|
-
**MANDATORY WORKFLOW REQUIREMENTS**:
|
|
364
|
-
|
|
365
|
-
{{#if IS_DESKTOP_PLATFORM}}
|
|
366
|
-
1. **Git Worktrees**: ALL code changes MUST use isolated git worktrees (\`{{WORKTREE_PREFIX}}NNN-slug\` branches)
|
|
367
|
-
2. **PR-Based Merges**: NO direct commits to \`{{DEFAULT_BRANCH}}\`. All changes via PR with automated review
|
|
368
|
-
3. **CI/CD Pipelines**: ALWAYS use CI/CD pipelines to deploy. Create ephemeral pipelines when needed
|
|
369
|
-
4. **Automated Review**: PRs require signoff from reviewer agents before merge
|
|
370
|
-
{{else}}
|
|
371
|
-
1. **Feature Branches**: ALL code changes MUST use isolated feature branches (\`{{WORKTREE_PREFIX}}description\`)
|
|
372
|
-
2. **PR-Based Merges**: NO direct commits to \`{{DEFAULT_BRANCH}}\`. All changes via PR
|
|
373
|
-
3. **Code Review**: PRs should be reviewed before merge
|
|
374
|
-
{{/if}}
|
|
606
|
+
- **Short-term**: \`{{MEMORY_DB_PATH}}\` (SQLite, last {{SHORT_TERM_LIMIT}} entries)
|
|
607
|
+
- **Long-term**: {{LONG_TERM_BACKEND}} at \`{{LONG_TERM_ENDPOINT}}\`
|
|
375
608
|
|
|
376
609
|
---
|
|
377
610
|
|
|
611
|
+
## Repository Structure
|
|
378
612
|
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
{{
|
|
382
|
-
### Cluster Contexts
|
|
383
|
-
|
|
384
|
-
\`\`\`bash
|
|
385
|
-
{{#each CLUSTERS}}
|
|
386
|
-
kubectl config use-context {{this.context}} # {{this.name}} ({{this.purpose}})
|
|
387
|
-
{{/each}}
|
|
613
|
+
\`\`\`
|
|
614
|
+
{{PROJECT_NAME}}/
|
|
615
|
+
{{{@REPOSITORY_STRUCTURE}}}
|
|
388
616
|
\`\`\`
|
|
389
617
|
|
|
390
|
-
{{
|
|
391
|
-
|
|
392
|
-
### URLs
|
|
393
|
-
|
|
394
|
-
{{#each URLS}}
|
|
395
|
-
- **{{this.name}}**: {{this.value}}
|
|
396
|
-
{{/each}}
|
|
618
|
+
{{#if ARCHITECTURE_OVERVIEW}}
|
|
619
|
+
## Architecture
|
|
397
620
|
|
|
621
|
+
{{{ARCHITECTURE_OVERVIEW}}}
|
|
398
622
|
{{/if}}
|
|
399
|
-
{{#if HAS_KEY_FILES}}
|
|
400
|
-
### Key Files
|
|
401
623
|
|
|
402
|
-
{{#
|
|
403
|
-
|
|
404
|
-
{{/each}}
|
|
624
|
+
{{#if CORE_COMPONENTS}}
|
|
625
|
+
## Components
|
|
405
626
|
|
|
627
|
+
{{{CORE_COMPONENTS}}}
|
|
406
628
|
{{/if}}
|
|
407
|
-
{{#if IS_DESKTOP_PLATFORM}}
|
|
408
|
-
### Essential Commands
|
|
409
629
|
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
uam worktree create <slug>
|
|
413
|
-
|
|
414
|
-
# Testing
|
|
415
|
-
{{TEST_COMMAND}}
|
|
416
|
-
|
|
417
|
-
# Linting
|
|
418
|
-
{{LINT_COMMAND}}
|
|
419
|
-
|
|
420
|
-
# Building
|
|
421
|
-
{{BUILD_COMMAND}}
|
|
422
|
-
{{#if HAS_TERRAFORM}}
|
|
630
|
+
{{#if TROUBLESHOOTING}}
|
|
631
|
+
## Troubleshooting
|
|
423
632
|
|
|
424
|
-
|
|
425
|
-
cd {{INFRA_PATH}} && terraform plan
|
|
633
|
+
{{{TROUBLESHOOTING}}}
|
|
426
634
|
{{/if}}
|
|
427
|
-
\`\`\`
|
|
428
635
|
|
|
429
|
-
{{/if}}
|
|
430
636
|
---
|
|
431
637
|
|
|
432
|
-
|
|
433
|
-
## Architecture
|
|
434
|
-
|
|
435
|
-
{{#each COMPONENTS}}
|
|
436
|
-
### {{this.name}} (\`{{this.path}}\`)
|
|
638
|
+
## Completion Checklist
|
|
437
639
|
|
|
438
|
-
-
|
|
439
|
-
|
|
440
|
-
-
|
|
640
|
+
- [ ] Tests pass
|
|
641
|
+
- [ ] Worktree used
|
|
642
|
+
- [ ] Memory updated
|
|
643
|
+
- [ ] PR created (not direct commit)
|
|
441
644
|
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
{
|
|
446
|
-
|
|
447
|
-
## Data Layer
|
|
645
|
+
</coding_guidelines>
|
|
646
|
+
`;
|
|
647
|
+
}
|
|
648
|
+
function getWebTemplate() {
|
|
649
|
+
return `<coding_guidelines>
|
|
448
650
|
|
|
449
|
-
{{
|
|
450
|
-
- **{{this.type}}**: {{this.purpose}}
|
|
451
|
-
{{/each}}
|
|
651
|
+
# AGENT.md - {{PROJECT_NAME}} Development Guide
|
|
452
652
|
|
|
453
|
-
|
|
653
|
+
You are an AI agent helping with this project. Follow best practices and maintain context.
|
|
454
654
|
|
|
655
|
+
{{#if DESCRIPTION}}
|
|
656
|
+
> {{DESCRIPTION}}
|
|
455
657
|
{{/if}}
|
|
456
|
-
{{#if HAS_AUTH}}
|
|
457
|
-
## Authentication
|
|
458
|
-
|
|
459
|
-
**Provider**: {{AUTH_PROVIDER}}
|
|
460
|
-
|
|
461
|
-
{{AUTH_DESCRIPTION}}
|
|
462
658
|
|
|
463
659
|
---
|
|
464
660
|
|
|
465
|
-
|
|
466
|
-
{{#if IS_DESKTOP_PLATFORM}}
|
|
467
|
-
{{#if HAS_CICD}}
|
|
468
|
-
## CI/CD ({{CICD_PLATFORM}})
|
|
661
|
+
## ⛔ MANDATORY RULES
|
|
469
662
|
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
| \`{{this.file}}\` | {{this.purpose}} |
|
|
474
|
-
{{/each}}
|
|
663
|
+
1. **BRANCH REQUIREMENT**: Never commit directly to {{DEFAULT_BRANCH}}. Use feature branches.
|
|
664
|
+
2. **MEMORY**: Store significant learnings to \`.uam/memory/\`
|
|
665
|
+
3. **TODO LIST**: Create todo list for multi-step tasks (3+ steps)
|
|
475
666
|
|
|
476
667
|
---
|
|
477
668
|
|
|
478
|
-
|
|
479
|
-
{{/if}}
|
|
480
|
-
{{#if HAS_TROUBLESHOOTING}}
|
|
481
|
-
## Troubleshooting
|
|
482
|
-
|
|
483
|
-
| Symptom | Solution |
|
|
484
|
-
|---------|----------|
|
|
485
|
-
{{#each TROUBLESHOOTING_HINTS}}
|
|
486
|
-
| {{this.symptom}} | {{this.solution}} |
|
|
487
|
-
{{/each}}
|
|
669
|
+
## Memory System
|
|
488
670
|
|
|
489
|
-
|
|
671
|
+
### Short-term (localStorage)
|
|
490
672
|
|
|
491
|
-
{{
|
|
492
|
-
## Required Workflow (MANDATORY)
|
|
673
|
+
Key: \`agent_context_{{PROJECT_NAME}}\`
|
|
493
674
|
|
|
494
|
-
|
|
495
|
-
### Git Worktree Workflow (ALL Changes)
|
|
675
|
+
### Long-term (GitHub: \`.uam/memory/\`)
|
|
496
676
|
|
|
497
|
-
|
|
677
|
+
Store memories as JSON files for persistent knowledge.
|
|
498
678
|
|
|
499
|
-
|
|
500
|
-
1. CREATE WORKTREE
|
|
501
|
-
uam worktree create <slug>
|
|
502
|
-
→ Creates {{WORKTREE_PREFIX}}NNN-slug branch in {{WORKTREE_DIR}}/NNN-slug/
|
|
503
|
-
|
|
504
|
-
2. DEVELOP
|
|
505
|
-
cd {{WORKTREE_DIR}}/NNN-slug/
|
|
506
|
-
→ Make changes, commit locally
|
|
507
|
-
|
|
508
|
-
3. CREATE PR (runs tests + triggers reviewers)
|
|
509
|
-
uam worktree pr <id>
|
|
510
|
-
→ Runs all offline tests (blocks if fail)
|
|
511
|
-
→ Pushes to origin
|
|
512
|
-
→ Creates PR with auto-generated description
|
|
513
|
-
→ Triggers reviewer agents
|
|
514
|
-
|
|
515
|
-
4. AUTOMATED REVIEW
|
|
516
|
-
→ Reviewer agents run in parallel (quality, security, performance, tests)
|
|
517
|
-
→ PR labeled: reviewer-approved OR needs-work
|
|
518
|
-
→ Auto-merge on approval
|
|
519
|
-
|
|
520
|
-
5. CLEANUP
|
|
521
|
-
uam worktree cleanup <id>
|
|
522
|
-
→ Removes worktree and deletes branch
|
|
523
|
-
\`\`\`
|
|
524
|
-
{{else}}
|
|
525
|
-
### Git Branch Workflow (ALL Changes)
|
|
679
|
+
---
|
|
526
680
|
|
|
527
|
-
|
|
681
|
+
## Repository Structure
|
|
528
682
|
|
|
529
683
|
\`\`\`
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
→ Creates isolated feature branch
|
|
533
|
-
|
|
534
|
-
2. DEVELOP
|
|
535
|
-
→ Make changes, commit locally
|
|
536
|
-
→ Keep commits atomic and well-described
|
|
537
|
-
|
|
538
|
-
3. CREATE PR
|
|
539
|
-
git push -u origin {{WORKTREE_PREFIX}}<description>
|
|
540
|
-
→ Push to remote
|
|
541
|
-
→ Create PR via GitHub/GitLab UI
|
|
542
|
-
|
|
543
|
-
4. CODE REVIEW
|
|
544
|
-
→ Request review from team members
|
|
545
|
-
→ Address feedback
|
|
546
|
-
|
|
547
|
-
5. MERGE & CLEANUP
|
|
548
|
-
→ Merge PR after approval
|
|
549
|
-
→ Delete feature branch
|
|
684
|
+
{{PROJECT_NAME}}/
|
|
685
|
+
{{{@REPOSITORY_STRUCTURE}}}
|
|
550
686
|
\`\`\`
|
|
551
|
-
{{/if}}
|
|
552
687
|
|
|
553
|
-
|
|
688
|
+
{{#if ARCHITECTURE_OVERVIEW}}
|
|
689
|
+
## Architecture
|
|
554
690
|
|
|
555
|
-
|
|
556
|
-
2. Check for known issues in troubleshooting section
|
|
557
|
-
{{#if IS_DESKTOP_PLATFORM}}
|
|
558
|
-
3. **Create a worktree for your changes**
|
|
559
|
-
{{else}}
|
|
560
|
-
3. **Create a feature branch for your changes**
|
|
691
|
+
{{{ARCHITECTURE_OVERVIEW}}}
|
|
561
692
|
{{/if}}
|
|
562
693
|
|
|
563
|
-
|
|
694
|
+
{{#if CORE_COMPONENTS}}
|
|
695
|
+
## Components
|
|
564
696
|
|
|
565
|
-
{{
|
|
566
|
-
1. **Create worktree**: \`uam worktree create <slug>\`
|
|
567
|
-
{{else}}
|
|
568
|
-
1. **Create branch**: \`git checkout -b {{WORKTREE_PREFIX}}<description>\`
|
|
569
|
-
{{/if}}
|
|
570
|
-
2. Update/create tests
|
|
571
|
-
3. Run \`{{TEST_COMMAND}}\`
|
|
572
|
-
4. Run linting and type checking
|
|
573
|
-
{{#if IS_DESKTOP_PLATFORM}}
|
|
574
|
-
5. **Create PR**: \`uam worktree pr <id>\`
|
|
575
|
-
{{else}}
|
|
576
|
-
5. **Create PR**: Push branch and open PR
|
|
697
|
+
{{{CORE_COMPONENTS}}}
|
|
577
698
|
{{/if}}
|
|
578
699
|
|
|
579
|
-
{{#if HAS_TERRAFORM}}
|
|
580
|
-
### For Infrastructure Changes
|
|
581
|
-
|
|
582
|
-
{{#if IS_DESKTOP_PLATFORM}}
|
|
583
|
-
1. **Create worktree** for Terraform changes
|
|
584
|
-
{{else}}
|
|
585
|
-
1. **Create branch** for Terraform changes
|
|
586
|
-
{{/if}}
|
|
587
|
-
2. Update Terraform in \`{{INFRA_PATH}}\`
|
|
588
|
-
3. Update CI/CD workflows if needed
|
|
589
|
-
4. Run \`terraform plan\`
|
|
590
|
-
5. Update secrets via GitHub Actions (not locally)
|
|
591
|
-
6. **Create PR** with review
|
|
592
|
-
|
|
593
|
-
{{/if}}
|
|
594
|
-
### Before Completing
|
|
595
|
-
|
|
596
|
-
1. All tests pass
|
|
597
|
-
2. PR created and reviewed
|
|
598
|
-
3. Update relevant documentation
|
|
599
|
-
|
|
600
700
|
---
|
|
601
701
|
|
|
702
|
+
## Workflow
|
|
602
703
|
|
|
603
|
-
{{
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
### Custom Droids (\`.factory/droids/\`)
|
|
607
|
-
|
|
608
|
-
{{#each DROIDS}}
|
|
609
|
-
- \`{{this}}\`
|
|
610
|
-
{{/each}}
|
|
611
|
-
|
|
612
|
-
{{#if HAS_COMMANDS}}
|
|
613
|
-
### Commands (\`.factory/commands/\`)
|
|
614
|
-
|
|
615
|
-
{{#each COMMANDS}}
|
|
616
|
-
- \`/{{this}}\`
|
|
617
|
-
{{/each}}
|
|
618
|
-
{{/if}}
|
|
704
|
+
1. Create feature branch: \`git checkout -b {{BRANCH_PREFIX}}<description>\`
|
|
705
|
+
2. Make changes, commit, push
|
|
706
|
+
3. Create PR via GitHub UI
|
|
619
707
|
|
|
620
708
|
---
|
|
621
709
|
|
|
622
|
-
|
|
623
|
-
## Completion Checklist
|
|
624
|
-
|
|
625
|
-
\`\`\`
|
|
626
|
-
[ ] Tests updated and passing
|
|
627
|
-
[ ] Linting/type checking passed
|
|
628
|
-
{{#if HAS_TERRAFORM}}
|
|
629
|
-
[ ] Terraform plan verified (if infra changed)
|
|
630
|
-
{{/if}}
|
|
631
|
-
[ ] Documentation updated
|
|
632
|
-
[ ] No secrets in code/commits
|
|
633
|
-
\`\`\`
|
|
634
|
-
|
|
635
|
-
---
|
|
710
|
+
## Quick Reference
|
|
636
711
|
|
|
637
|
-
**
|
|
638
|
-
**
|
|
712
|
+
- **Test**: \`{{TEST_COMMAND}}\`
|
|
713
|
+
- **Build**: \`{{BUILD_COMMAND}}\`
|
|
714
|
+
- **Lint**: \`{{LINT_COMMAND}}\`
|
|
639
715
|
|
|
640
716
|
</coding_guidelines>
|
|
641
717
|
`;
|