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