create-universal-ai-context 2.4.0 → 2.6.0-final
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/LICENSE +21 -21
- package/README.md +331 -294
- package/bin/create-ai-context.js +1507 -764
- package/lib/adapters/aider.js +131 -131
- package/lib/adapters/antigravity.js +205 -205
- package/lib/adapters/claude.js +397 -397
- package/lib/adapters/cline.js +125 -125
- package/lib/adapters/continue.js +138 -138
- package/lib/adapters/copilot.js +131 -131
- package/lib/adapters/index.js +78 -78
- package/lib/adapters/windsurf.js +138 -138
- package/lib/ai-context-generator.js +234 -234
- package/lib/ai-orchestrator.js +432 -432
- package/lib/call-tracer.js +444 -444
- package/lib/content-preservation.js +243 -243
- package/lib/cross-tool-sync/file-watcher.js +274 -274
- package/lib/cross-tool-sync/index.js +41 -40
- package/lib/cross-tool-sync/sync-manager.js +540 -512
- package/lib/cross-tool-sync/sync-service.js +297 -297
- package/lib/detector.js +726 -726
- package/lib/doc-discovery.js +741 -741
- package/lib/drift-checker.js +920 -920
- package/lib/environment-detector.js +239 -239
- package/lib/index.js +399 -399
- package/lib/install-hooks.js +82 -82
- package/lib/installer.js +419 -419
- package/lib/migrate.js +328 -328
- package/lib/placeholder.js +632 -632
- package/lib/prompts.js +341 -341
- package/lib/smart-merge.js +540 -540
- package/lib/spinner.js +60 -60
- package/lib/static-analyzer.js +729 -729
- package/lib/template-coordination.js +148 -148
- package/lib/template-populator.js +843 -843
- package/lib/template-renderer.js +392 -392
- package/lib/utils/fs-wrapper.js +79 -79
- package/lib/utils/path-utils.js +60 -60
- package/lib/validate.js +155 -155
- package/package.json +1 -1
- package/templates/AI_CONTEXT.md.template +245 -245
- package/templates/base/README.md +260 -257
- package/templates/base/RPI_WORKFLOW_PLAN.md +325 -320
- package/templates/base/agents/api-developer.md +76 -76
- package/templates/base/agents/context-engineer.md +525 -525
- package/templates/base/agents/core-architect.md +76 -76
- package/templates/base/agents/database-ops.md +76 -76
- package/templates/base/agents/deployment-ops.md +76 -76
- package/templates/base/agents/integration-hub.md +76 -76
- package/templates/base/analytics/README.md +114 -114
- package/templates/base/automation/config.json +58 -58
- package/templates/base/automation/generators/code-mapper.js +308 -308
- package/templates/base/automation/generators/index-builder.js +321 -321
- package/templates/base/automation/hooks/post-commit.sh +83 -83
- package/templates/base/automation/hooks/pre-commit.sh +103 -103
- package/templates/base/ci-templates/README.md +108 -108
- package/templates/base/ci-templates/github-actions/context-check.yml +144 -144
- package/templates/base/ci-templates/github-actions/validate-docs.yml +105 -105
- package/templates/base/commands/analytics.md +238 -238
- package/templates/base/commands/auto-sync.md +172 -172
- package/templates/base/commands/collab.md +194 -194
- package/templates/base/commands/context-optimize.md +226 -0
- package/templates/base/commands/help.md +485 -450
- package/templates/base/commands/rpi-implement.md +164 -115
- package/templates/base/commands/rpi-plan.md +147 -93
- package/templates/base/commands/rpi-research.md +145 -88
- package/templates/base/commands/session-resume.md +144 -144
- package/templates/base/commands/session-save.md +112 -112
- package/templates/base/commands/validate-all.md +77 -77
- package/templates/base/commands/verify-docs-current.md +86 -86
- package/templates/base/config/base.json +57 -57
- package/templates/base/config/environments/development.json +13 -13
- package/templates/base/config/environments/production.json +17 -17
- package/templates/base/config/environments/staging.json +13 -13
- package/templates/base/config/local.json.example +21 -21
- package/templates/base/context/.meta/generated-at.json +18 -18
- package/templates/base/context/ARCHITECTURE_SNAPSHOT.md +156 -156
- package/templates/base/context/CODE_TO_WORKFLOW_MAP.md +94 -94
- package/templates/base/context/FILE_OWNERSHIP.md +57 -57
- package/templates/base/context/INTEGRATION_POINTS.md +92 -92
- package/templates/base/context/KNOWN_GOTCHAS.md +195 -195
- package/templates/base/context/TESTING_MAP.md +95 -95
- package/templates/base/context/WORKFLOW_INDEX.md +129 -129
- package/templates/base/context/workflows/WORKFLOW_TEMPLATE.md +294 -294
- package/templates/base/indexes/agents/CAPABILITY_MATRIX.md +255 -255
- package/templates/base/indexes/agents/CATEGORY_INDEX.md +44 -44
- package/templates/base/indexes/code/CATEGORY_INDEX.md +38 -38
- package/templates/base/indexes/routing/CATEGORY_INDEX.md +39 -39
- package/templates/base/indexes/search/CATEGORY_INDEX.md +39 -39
- package/templates/base/indexes/workflows/CATEGORY_INDEX.md +38 -38
- package/templates/base/knowledge/README.md +98 -98
- package/templates/base/knowledge/sessions/README.md +88 -88
- package/templates/base/knowledge/sessions/TEMPLATE.md +150 -150
- package/templates/base/knowledge/shared/decisions/0001-adopt-context-engineering.md +144 -144
- package/templates/base/knowledge/shared/decisions/README.md +49 -49
- package/templates/base/knowledge/shared/decisions/TEMPLATE.md +123 -123
- package/templates/base/knowledge/shared/patterns/README.md +62 -62
- package/templates/base/knowledge/shared/patterns/TEMPLATE.md +120 -120
- package/templates/base/plans/PLAN_TEMPLATE.md +316 -250
- package/templates/base/research/RESEARCH_TEMPLATE.md +245 -153
- package/templates/base/schemas/agent.schema.json +141 -141
- package/templates/base/schemas/anchors.schema.json +54 -54
- package/templates/base/schemas/automation.schema.json +93 -93
- package/templates/base/schemas/command.schema.json +134 -134
- package/templates/base/schemas/hashes.schema.json +40 -40
- package/templates/base/schemas/manifest.schema.json +117 -117
- package/templates/base/schemas/plan.schema.json +136 -136
- package/templates/base/schemas/research.schema.json +115 -115
- package/templates/base/schemas/roles.schema.json +34 -34
- package/templates/base/schemas/session.schema.json +77 -77
- package/templates/base/schemas/settings.schema.json +244 -244
- package/templates/base/schemas/staleness.schema.json +53 -53
- package/templates/base/schemas/team-config.schema.json +42 -42
- package/templates/base/schemas/workflow.schema.json +126 -126
- package/templates/base/session/checkpoints/.gitkeep +2 -2
- package/templates/base/session/current/state.json +20 -20
- package/templates/base/session/history/.gitkeep +2 -2
- package/templates/base/settings.json +3 -3
- package/templates/base/standards/COMPATIBILITY.md +219 -219
- package/templates/base/standards/EXTENSION_GUIDELINES.md +280 -280
- package/templates/base/standards/QUALITY_CHECKLIST.md +211 -211
- package/templates/base/standards/README.md +66 -66
- package/templates/base/sync/anchors.json +6 -6
- package/templates/base/sync/hashes.json +6 -6
- package/templates/base/sync/staleness.json +10 -10
- package/templates/base/team/README.md +168 -168
- package/templates/base/team/config.json +79 -79
- package/templates/base/team/roles.json +145 -145
- package/templates/base/tools/bin/claude-context.js +151 -151
- package/templates/base/tools/lib/anchor-resolver.js +276 -276
- package/templates/base/tools/lib/config-loader.js +363 -363
- package/templates/base/tools/lib/detector.js +350 -350
- package/templates/base/tools/lib/diagnose.js +206 -206
- package/templates/base/tools/lib/drift-detector.js +373 -373
- package/templates/base/tools/lib/errors.js +199 -199
- package/templates/base/tools/lib/index.js +36 -36
- package/templates/base/tools/lib/init.js +192 -192
- package/templates/base/tools/lib/logger.js +230 -230
- package/templates/base/tools/lib/placeholder.js +201 -201
- package/templates/base/tools/lib/session-manager.js +354 -354
- package/templates/base/tools/lib/validate.js +521 -521
- package/templates/base/tools/package.json +49 -49
- package/templates/handlebars/aider-config.hbs +146 -80
- package/templates/handlebars/antigravity.hbs +377 -377
- package/templates/handlebars/claude.hbs +183 -183
- package/templates/handlebars/cline.hbs +62 -62
- package/templates/handlebars/continue-config.hbs +116 -116
- package/templates/handlebars/copilot.hbs +130 -130
- package/templates/handlebars/partials/gotcha-list.hbs +11 -11
- package/templates/handlebars/partials/header.hbs +3 -3
- package/templates/handlebars/partials/workflow-summary.hbs +16 -16
- package/templates/handlebars/windsurf-rules.hbs +69 -69
- package/templates/hooks/post-commit.hbs +28 -29
- package/templates/hooks/pre-commit.hbs +46 -46
|
@@ -1,321 +1,321 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Index Builder - Rebuilds category indexes from content
|
|
3
|
-
*
|
|
4
|
-
* Scans workflow and agent files to regenerate index files
|
|
5
|
-
* with accurate counts and references.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
const fs = require('fs');
|
|
9
|
-
const path = require('path');
|
|
10
|
-
const glob = require('glob');
|
|
11
|
-
|
|
12
|
-
const CLAUDE_DIR = path.join(__dirname, '..', '..');
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Parse frontmatter from markdown file
|
|
16
|
-
*/
|
|
17
|
-
function parseFrontmatter(content) {
|
|
18
|
-
const match = content.match(/^---\n([\s\S]*?)\n---/);
|
|
19
|
-
if (!match) return {};
|
|
20
|
-
|
|
21
|
-
const frontmatter = {};
|
|
22
|
-
const lines = match[1].split('\n');
|
|
23
|
-
for (const line of lines) {
|
|
24
|
-
const [key, ...valueParts] = line.split(':');
|
|
25
|
-
if (key && valueParts.length > 0) {
|
|
26
|
-
frontmatter[key.trim()] = valueParts.join(':').trim();
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
return frontmatter;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Scan workflows directory and collect metadata
|
|
34
|
-
*/
|
|
35
|
-
function scanWorkflows() {
|
|
36
|
-
const workflowsDir = path.join(CLAUDE_DIR, 'context', 'workflows');
|
|
37
|
-
const workflows = [];
|
|
38
|
-
|
|
39
|
-
if (!fs.existsSync(workflowsDir)) {
|
|
40
|
-
return workflows;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
const files = fs.readdirSync(workflowsDir).filter(f => f.endsWith('.md'));
|
|
44
|
-
|
|
45
|
-
for (const file of files) {
|
|
46
|
-
if (file === 'WORKFLOW_TEMPLATE.md') continue;
|
|
47
|
-
|
|
48
|
-
try {
|
|
49
|
-
const filePath = path.join(workflowsDir, file);
|
|
50
|
-
const content = fs.readFileSync(filePath, 'utf-8');
|
|
51
|
-
const frontmatter = parseFrontmatter(content);
|
|
52
|
-
|
|
53
|
-
// Extract title from first heading
|
|
54
|
-
const titleMatch = content.match(/^#\s+(.+)$/m);
|
|
55
|
-
const title = titleMatch ? titleMatch[1] : file.replace('.md', '');
|
|
56
|
-
|
|
57
|
-
workflows.push({
|
|
58
|
-
file: file,
|
|
59
|
-
name: frontmatter.name || title,
|
|
60
|
-
category: frontmatter.category || 'uncategorized',
|
|
61
|
-
complexity: frontmatter.complexity || 'medium',
|
|
62
|
-
description: frontmatter.description || '',
|
|
63
|
-
lastUpdated: frontmatter.last_updated || null
|
|
64
|
-
});
|
|
65
|
-
} catch (error) {
|
|
66
|
-
console.error(`Error parsing ${file}:`, error.message);
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
return workflows;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* Scan agents directory and collect metadata
|
|
75
|
-
*/
|
|
76
|
-
function scanAgents() {
|
|
77
|
-
const agentsDir = path.join(CLAUDE_DIR, 'agents');
|
|
78
|
-
const agents = [];
|
|
79
|
-
|
|
80
|
-
if (!fs.existsSync(agentsDir)) {
|
|
81
|
-
return agents;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
const files = fs.readdirSync(agentsDir).filter(f => f.endsWith('.md'));
|
|
85
|
-
|
|
86
|
-
for (const file of files) {
|
|
87
|
-
try {
|
|
88
|
-
const filePath = path.join(agentsDir, file);
|
|
89
|
-
const content = fs.readFileSync(filePath, 'utf-8');
|
|
90
|
-
const frontmatter = parseFrontmatter(content);
|
|
91
|
-
|
|
92
|
-
// Extract title from first heading
|
|
93
|
-
const titleMatch = content.match(/^#\s+(.+)$/m);
|
|
94
|
-
const title = titleMatch ? titleMatch[1] : file.replace('.md', '');
|
|
95
|
-
|
|
96
|
-
agents.push({
|
|
97
|
-
file: file,
|
|
98
|
-
name: frontmatter.name || title,
|
|
99
|
-
role: frontmatter.role || 'general',
|
|
100
|
-
complexity: frontmatter.complexity || 'medium',
|
|
101
|
-
description: frontmatter.description || ''
|
|
102
|
-
});
|
|
103
|
-
} catch (error) {
|
|
104
|
-
console.error(`Error parsing ${file}:`, error.message);
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
return agents;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
* Scan commands directory and collect metadata
|
|
113
|
-
*/
|
|
114
|
-
function scanCommands() {
|
|
115
|
-
const commandsDir = path.join(CLAUDE_DIR, 'commands');
|
|
116
|
-
const commands = [];
|
|
117
|
-
|
|
118
|
-
if (!fs.existsSync(commandsDir)) {
|
|
119
|
-
return commands;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
const files = fs.readdirSync(commandsDir).filter(f => f.endsWith('.md'));
|
|
123
|
-
|
|
124
|
-
for (const file of files) {
|
|
125
|
-
try {
|
|
126
|
-
const filePath = path.join(commandsDir, file);
|
|
127
|
-
const content = fs.readFileSync(filePath, 'utf-8');
|
|
128
|
-
const frontmatter = parseFrontmatter(content);
|
|
129
|
-
|
|
130
|
-
commands.push({
|
|
131
|
-
file: file,
|
|
132
|
-
name: frontmatter.name || '/' + file.replace('.md', ''),
|
|
133
|
-
category: frontmatter.category || 'general',
|
|
134
|
-
description: frontmatter.description || ''
|
|
135
|
-
});
|
|
136
|
-
} catch (error) {
|
|
137
|
-
console.error(`Error parsing ${file}:`, error.message);
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
return commands;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
/**
|
|
145
|
-
* Generate workflow category index content
|
|
146
|
-
*/
|
|
147
|
-
function generateWorkflowIndex(workflows) {
|
|
148
|
-
const now = new Date().toISOString();
|
|
149
|
-
|
|
150
|
-
// Group by category
|
|
151
|
-
const byCategory = {};
|
|
152
|
-
for (const wf of workflows) {
|
|
153
|
-
if (!byCategory[wf.category]) {
|
|
154
|
-
byCategory[wf.category] = [];
|
|
155
|
-
}
|
|
156
|
-
byCategory[wf.category].push(wf);
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
let content = `# Workflow Category Index
|
|
160
|
-
|
|
161
|
-
> **Auto-generated:** ${now}
|
|
162
|
-
> **Total Workflows:** ${workflows.length}
|
|
163
|
-
|
|
164
|
-
This index organizes all documented workflows by category.
|
|
165
|
-
|
|
166
|
-
---
|
|
167
|
-
|
|
168
|
-
## Quick Navigation
|
|
169
|
-
|
|
170
|
-
| Category | Count | Description |
|
|
171
|
-
|----------|-------|-------------|
|
|
172
|
-
`;
|
|
173
|
-
|
|
174
|
-
for (const [category, wfs] of Object.entries(byCategory).sort()) {
|
|
175
|
-
content += `| ${category} | ${wfs.length} | ${category} workflows |\n`;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
content += `\n---\n\n`;
|
|
179
|
-
|
|
180
|
-
// Detail by category
|
|
181
|
-
for (const [category, wfs] of Object.entries(byCategory).sort()) {
|
|
182
|
-
content += `## ${category.charAt(0).toUpperCase() + category.slice(1)}\n\n`;
|
|
183
|
-
content += `| Workflow | Complexity | Description |\n`;
|
|
184
|
-
content += `|----------|------------|-------------|\n`;
|
|
185
|
-
|
|
186
|
-
for (const wf of wfs.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
187
|
-
const link = `[${wf.name}](../../context/workflows/${wf.file})`;
|
|
188
|
-
content += `| ${link} | ${wf.complexity} | ${wf.description || '-'} |\n`;
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
content += `\n`;
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
content += `---\n\n*Auto-generated by index-builder.js*\n`;
|
|
195
|
-
|
|
196
|
-
return content;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
/**
|
|
200
|
-
* Generate agent category index content
|
|
201
|
-
*/
|
|
202
|
-
function generateAgentIndex(agents) {
|
|
203
|
-
const now = new Date().toISOString();
|
|
204
|
-
|
|
205
|
-
let content = `# Agent Category Index
|
|
206
|
-
|
|
207
|
-
> **Auto-generated:** ${now}
|
|
208
|
-
> **Total Agents:** ${agents.length}
|
|
209
|
-
|
|
210
|
-
This index lists all specialized agents and their capabilities.
|
|
211
|
-
|
|
212
|
-
---
|
|
213
|
-
|
|
214
|
-
## Available Agents
|
|
215
|
-
|
|
216
|
-
| Agent | Role | Complexity | Description |
|
|
217
|
-
|-------|------|------------|-------------|
|
|
218
|
-
`;
|
|
219
|
-
|
|
220
|
-
for (const agent of agents.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
221
|
-
const link = `[${agent.name}](../../agents/${agent.file})`;
|
|
222
|
-
content += `| ${link} | ${agent.role} | ${agent.complexity} | ${agent.description || '-'} |\n`;
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
content += `\n---\n\n## Agent Selection Guide\n\n`;
|
|
226
|
-
content += `Choose an agent based on your task:\n\n`;
|
|
227
|
-
content += `- **context-engineer** - Initial setup, documentation generation\n`;
|
|
228
|
-
content += `- **core-architect** - System design, architecture decisions\n`;
|
|
229
|
-
content += `- **database-ops** - Schema, migrations, queries\n`;
|
|
230
|
-
content += `- **api-developer** - Endpoints, contracts, REST/GraphQL\n`;
|
|
231
|
-
content += `- **integration-hub** - External services, webhooks\n`;
|
|
232
|
-
content += `- **deployment-ops** - CI/CD, infrastructure\n`;
|
|
233
|
-
content += `\n---\n\n*Auto-generated by index-builder.js*\n`;
|
|
234
|
-
|
|
235
|
-
return content;
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
/**
|
|
239
|
-
* Build all indexes
|
|
240
|
-
*/
|
|
241
|
-
function buildAll(options = {}) {
|
|
242
|
-
const { dryRun = false, verbose = false } = options;
|
|
243
|
-
const results = [];
|
|
244
|
-
|
|
245
|
-
console.log('Scanning content...');
|
|
246
|
-
|
|
247
|
-
// Scan all content
|
|
248
|
-
const workflows = scanWorkflows();
|
|
249
|
-
const agents = scanAgents();
|
|
250
|
-
const commands = scanCommands();
|
|
251
|
-
|
|
252
|
-
console.log(`Found: ${workflows.length} workflows, ${agents.length} agents, ${commands.length} commands`);
|
|
253
|
-
|
|
254
|
-
// Generate workflow index
|
|
255
|
-
const workflowIndexContent = generateWorkflowIndex(workflows);
|
|
256
|
-
const workflowIndexPath = path.join(CLAUDE_DIR, 'indexes', 'workflows', 'CATEGORY_INDEX.md');
|
|
257
|
-
|
|
258
|
-
if (!dryRun) {
|
|
259
|
-
fs.writeFileSync(workflowIndexPath, workflowIndexContent);
|
|
260
|
-
console.log(`Generated: ${workflowIndexPath}`);
|
|
261
|
-
}
|
|
262
|
-
results.push({ type: 'workflow-index', path: workflowIndexPath, itemCount: workflows.length });
|
|
263
|
-
|
|
264
|
-
// Generate agent index
|
|
265
|
-
const agentIndexContent = generateAgentIndex(agents);
|
|
266
|
-
const agentIndexPath = path.join(CLAUDE_DIR, 'indexes', 'agents', 'CATEGORY_INDEX.md');
|
|
267
|
-
|
|
268
|
-
if (!dryRun) {
|
|
269
|
-
fs.writeFileSync(agentIndexPath, agentIndexContent);
|
|
270
|
-
console.log(`Generated: ${agentIndexPath}`);
|
|
271
|
-
}
|
|
272
|
-
results.push({ type: 'agent-index', path: agentIndexPath, itemCount: agents.length });
|
|
273
|
-
|
|
274
|
-
// Update generation metadata
|
|
275
|
-
if (!dryRun) {
|
|
276
|
-
const metaPath = path.join(CLAUDE_DIR, 'context', '.meta', 'generated-at.json');
|
|
277
|
-
let metadata = {};
|
|
278
|
-
if (fs.existsSync(metaPath)) {
|
|
279
|
-
try {
|
|
280
|
-
metadata = JSON.parse(fs.readFileSync(metaPath, 'utf-8'));
|
|
281
|
-
} catch (e) {}
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
metadata['WORKFLOW_CATEGORY_INDEX'] = {
|
|
285
|
-
generatedAt: new Date().toISOString(),
|
|
286
|
-
itemCount: workflows.length
|
|
287
|
-
};
|
|
288
|
-
metadata['AGENT_CATEGORY_INDEX'] = {
|
|
289
|
-
generatedAt: new Date().toISOString(),
|
|
290
|
-
itemCount: agents.length
|
|
291
|
-
};
|
|
292
|
-
|
|
293
|
-
const metaDir = path.dirname(metaPath);
|
|
294
|
-
if (!fs.existsSync(metaDir)) {
|
|
295
|
-
fs.mkdirSync(metaDir, { recursive: true });
|
|
296
|
-
}
|
|
297
|
-
fs.writeFileSync(metaPath, JSON.stringify(metadata, null, 2));
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
return { success: true, results };
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
// CLI execution
|
|
304
|
-
if (require.main === module) {
|
|
305
|
-
const args = process.argv.slice(2);
|
|
306
|
-
const dryRun = args.includes('--dry-run');
|
|
307
|
-
const verbose = args.includes('--verbose') || args.includes('-v');
|
|
308
|
-
|
|
309
|
-
const result = buildAll({ dryRun, verbose });
|
|
310
|
-
console.log(`\nIndex build ${result.success ? 'complete' : 'failed'}`);
|
|
311
|
-
process.exit(result.success ? 0 : 1);
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
module.exports = {
|
|
315
|
-
buildAll,
|
|
316
|
-
scanWorkflows,
|
|
317
|
-
scanAgents,
|
|
318
|
-
scanCommands,
|
|
319
|
-
generateWorkflowIndex,
|
|
320
|
-
generateAgentIndex
|
|
321
|
-
};
|
|
1
|
+
/**
|
|
2
|
+
* Index Builder - Rebuilds category indexes from content
|
|
3
|
+
*
|
|
4
|
+
* Scans workflow and agent files to regenerate index files
|
|
5
|
+
* with accurate counts and references.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const fs = require('fs');
|
|
9
|
+
const path = require('path');
|
|
10
|
+
const glob = require('glob');
|
|
11
|
+
|
|
12
|
+
const CLAUDE_DIR = path.join(__dirname, '..', '..');
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Parse frontmatter from markdown file
|
|
16
|
+
*/
|
|
17
|
+
function parseFrontmatter(content) {
|
|
18
|
+
const match = content.match(/^---\n([\s\S]*?)\n---/);
|
|
19
|
+
if (!match) return {};
|
|
20
|
+
|
|
21
|
+
const frontmatter = {};
|
|
22
|
+
const lines = match[1].split('\n');
|
|
23
|
+
for (const line of lines) {
|
|
24
|
+
const [key, ...valueParts] = line.split(':');
|
|
25
|
+
if (key && valueParts.length > 0) {
|
|
26
|
+
frontmatter[key.trim()] = valueParts.join(':').trim();
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return frontmatter;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Scan workflows directory and collect metadata
|
|
34
|
+
*/
|
|
35
|
+
function scanWorkflows() {
|
|
36
|
+
const workflowsDir = path.join(CLAUDE_DIR, 'context', 'workflows');
|
|
37
|
+
const workflows = [];
|
|
38
|
+
|
|
39
|
+
if (!fs.existsSync(workflowsDir)) {
|
|
40
|
+
return workflows;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const files = fs.readdirSync(workflowsDir).filter(f => f.endsWith('.md'));
|
|
44
|
+
|
|
45
|
+
for (const file of files) {
|
|
46
|
+
if (file === 'WORKFLOW_TEMPLATE.md') continue;
|
|
47
|
+
|
|
48
|
+
try {
|
|
49
|
+
const filePath = path.join(workflowsDir, file);
|
|
50
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
51
|
+
const frontmatter = parseFrontmatter(content);
|
|
52
|
+
|
|
53
|
+
// Extract title from first heading
|
|
54
|
+
const titleMatch = content.match(/^#\s+(.+)$/m);
|
|
55
|
+
const title = titleMatch ? titleMatch[1] : file.replace('.md', '');
|
|
56
|
+
|
|
57
|
+
workflows.push({
|
|
58
|
+
file: file,
|
|
59
|
+
name: frontmatter.name || title,
|
|
60
|
+
category: frontmatter.category || 'uncategorized',
|
|
61
|
+
complexity: frontmatter.complexity || 'medium',
|
|
62
|
+
description: frontmatter.description || '',
|
|
63
|
+
lastUpdated: frontmatter.last_updated || null
|
|
64
|
+
});
|
|
65
|
+
} catch (error) {
|
|
66
|
+
console.error(`Error parsing ${file}:`, error.message);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return workflows;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Scan agents directory and collect metadata
|
|
75
|
+
*/
|
|
76
|
+
function scanAgents() {
|
|
77
|
+
const agentsDir = path.join(CLAUDE_DIR, 'agents');
|
|
78
|
+
const agents = [];
|
|
79
|
+
|
|
80
|
+
if (!fs.existsSync(agentsDir)) {
|
|
81
|
+
return agents;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const files = fs.readdirSync(agentsDir).filter(f => f.endsWith('.md'));
|
|
85
|
+
|
|
86
|
+
for (const file of files) {
|
|
87
|
+
try {
|
|
88
|
+
const filePath = path.join(agentsDir, file);
|
|
89
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
90
|
+
const frontmatter = parseFrontmatter(content);
|
|
91
|
+
|
|
92
|
+
// Extract title from first heading
|
|
93
|
+
const titleMatch = content.match(/^#\s+(.+)$/m);
|
|
94
|
+
const title = titleMatch ? titleMatch[1] : file.replace('.md', '');
|
|
95
|
+
|
|
96
|
+
agents.push({
|
|
97
|
+
file: file,
|
|
98
|
+
name: frontmatter.name || title,
|
|
99
|
+
role: frontmatter.role || 'general',
|
|
100
|
+
complexity: frontmatter.complexity || 'medium',
|
|
101
|
+
description: frontmatter.description || ''
|
|
102
|
+
});
|
|
103
|
+
} catch (error) {
|
|
104
|
+
console.error(`Error parsing ${file}:`, error.message);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return agents;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Scan commands directory and collect metadata
|
|
113
|
+
*/
|
|
114
|
+
function scanCommands() {
|
|
115
|
+
const commandsDir = path.join(CLAUDE_DIR, 'commands');
|
|
116
|
+
const commands = [];
|
|
117
|
+
|
|
118
|
+
if (!fs.existsSync(commandsDir)) {
|
|
119
|
+
return commands;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const files = fs.readdirSync(commandsDir).filter(f => f.endsWith('.md'));
|
|
123
|
+
|
|
124
|
+
for (const file of files) {
|
|
125
|
+
try {
|
|
126
|
+
const filePath = path.join(commandsDir, file);
|
|
127
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
128
|
+
const frontmatter = parseFrontmatter(content);
|
|
129
|
+
|
|
130
|
+
commands.push({
|
|
131
|
+
file: file,
|
|
132
|
+
name: frontmatter.name || '/' + file.replace('.md', ''),
|
|
133
|
+
category: frontmatter.category || 'general',
|
|
134
|
+
description: frontmatter.description || ''
|
|
135
|
+
});
|
|
136
|
+
} catch (error) {
|
|
137
|
+
console.error(`Error parsing ${file}:`, error.message);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return commands;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Generate workflow category index content
|
|
146
|
+
*/
|
|
147
|
+
function generateWorkflowIndex(workflows) {
|
|
148
|
+
const now = new Date().toISOString();
|
|
149
|
+
|
|
150
|
+
// Group by category
|
|
151
|
+
const byCategory = {};
|
|
152
|
+
for (const wf of workflows) {
|
|
153
|
+
if (!byCategory[wf.category]) {
|
|
154
|
+
byCategory[wf.category] = [];
|
|
155
|
+
}
|
|
156
|
+
byCategory[wf.category].push(wf);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
let content = `# Workflow Category Index
|
|
160
|
+
|
|
161
|
+
> **Auto-generated:** ${now}
|
|
162
|
+
> **Total Workflows:** ${workflows.length}
|
|
163
|
+
|
|
164
|
+
This index organizes all documented workflows by category.
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
## Quick Navigation
|
|
169
|
+
|
|
170
|
+
| Category | Count | Description |
|
|
171
|
+
|----------|-------|-------------|
|
|
172
|
+
`;
|
|
173
|
+
|
|
174
|
+
for (const [category, wfs] of Object.entries(byCategory).sort()) {
|
|
175
|
+
content += `| ${category} | ${wfs.length} | ${category} workflows |\n`;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
content += `\n---\n\n`;
|
|
179
|
+
|
|
180
|
+
// Detail by category
|
|
181
|
+
for (const [category, wfs] of Object.entries(byCategory).sort()) {
|
|
182
|
+
content += `## ${category.charAt(0).toUpperCase() + category.slice(1)}\n\n`;
|
|
183
|
+
content += `| Workflow | Complexity | Description |\n`;
|
|
184
|
+
content += `|----------|------------|-------------|\n`;
|
|
185
|
+
|
|
186
|
+
for (const wf of wfs.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
187
|
+
const link = `[${wf.name}](../../context/workflows/${wf.file})`;
|
|
188
|
+
content += `| ${link} | ${wf.complexity} | ${wf.description || '-'} |\n`;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
content += `\n`;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
content += `---\n\n*Auto-generated by index-builder.js*\n`;
|
|
195
|
+
|
|
196
|
+
return content;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Generate agent category index content
|
|
201
|
+
*/
|
|
202
|
+
function generateAgentIndex(agents) {
|
|
203
|
+
const now = new Date().toISOString();
|
|
204
|
+
|
|
205
|
+
let content = `# Agent Category Index
|
|
206
|
+
|
|
207
|
+
> **Auto-generated:** ${now}
|
|
208
|
+
> **Total Agents:** ${agents.length}
|
|
209
|
+
|
|
210
|
+
This index lists all specialized agents and their capabilities.
|
|
211
|
+
|
|
212
|
+
---
|
|
213
|
+
|
|
214
|
+
## Available Agents
|
|
215
|
+
|
|
216
|
+
| Agent | Role | Complexity | Description |
|
|
217
|
+
|-------|------|------------|-------------|
|
|
218
|
+
`;
|
|
219
|
+
|
|
220
|
+
for (const agent of agents.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
221
|
+
const link = `[${agent.name}](../../agents/${agent.file})`;
|
|
222
|
+
content += `| ${link} | ${agent.role} | ${agent.complexity} | ${agent.description || '-'} |\n`;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
content += `\n---\n\n## Agent Selection Guide\n\n`;
|
|
226
|
+
content += `Choose an agent based on your task:\n\n`;
|
|
227
|
+
content += `- **context-engineer** - Initial setup, documentation generation\n`;
|
|
228
|
+
content += `- **core-architect** - System design, architecture decisions\n`;
|
|
229
|
+
content += `- **database-ops** - Schema, migrations, queries\n`;
|
|
230
|
+
content += `- **api-developer** - Endpoints, contracts, REST/GraphQL\n`;
|
|
231
|
+
content += `- **integration-hub** - External services, webhooks\n`;
|
|
232
|
+
content += `- **deployment-ops** - CI/CD, infrastructure\n`;
|
|
233
|
+
content += `\n---\n\n*Auto-generated by index-builder.js*\n`;
|
|
234
|
+
|
|
235
|
+
return content;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Build all indexes
|
|
240
|
+
*/
|
|
241
|
+
function buildAll(options = {}) {
|
|
242
|
+
const { dryRun = false, verbose = false } = options;
|
|
243
|
+
const results = [];
|
|
244
|
+
|
|
245
|
+
console.log('Scanning content...');
|
|
246
|
+
|
|
247
|
+
// Scan all content
|
|
248
|
+
const workflows = scanWorkflows();
|
|
249
|
+
const agents = scanAgents();
|
|
250
|
+
const commands = scanCommands();
|
|
251
|
+
|
|
252
|
+
console.log(`Found: ${workflows.length} workflows, ${agents.length} agents, ${commands.length} commands`);
|
|
253
|
+
|
|
254
|
+
// Generate workflow index
|
|
255
|
+
const workflowIndexContent = generateWorkflowIndex(workflows);
|
|
256
|
+
const workflowIndexPath = path.join(CLAUDE_DIR, 'indexes', 'workflows', 'CATEGORY_INDEX.md');
|
|
257
|
+
|
|
258
|
+
if (!dryRun) {
|
|
259
|
+
fs.writeFileSync(workflowIndexPath, workflowIndexContent);
|
|
260
|
+
console.log(`Generated: ${workflowIndexPath}`);
|
|
261
|
+
}
|
|
262
|
+
results.push({ type: 'workflow-index', path: workflowIndexPath, itemCount: workflows.length });
|
|
263
|
+
|
|
264
|
+
// Generate agent index
|
|
265
|
+
const agentIndexContent = generateAgentIndex(agents);
|
|
266
|
+
const agentIndexPath = path.join(CLAUDE_DIR, 'indexes', 'agents', 'CATEGORY_INDEX.md');
|
|
267
|
+
|
|
268
|
+
if (!dryRun) {
|
|
269
|
+
fs.writeFileSync(agentIndexPath, agentIndexContent);
|
|
270
|
+
console.log(`Generated: ${agentIndexPath}`);
|
|
271
|
+
}
|
|
272
|
+
results.push({ type: 'agent-index', path: agentIndexPath, itemCount: agents.length });
|
|
273
|
+
|
|
274
|
+
// Update generation metadata
|
|
275
|
+
if (!dryRun) {
|
|
276
|
+
const metaPath = path.join(CLAUDE_DIR, 'context', '.meta', 'generated-at.json');
|
|
277
|
+
let metadata = {};
|
|
278
|
+
if (fs.existsSync(metaPath)) {
|
|
279
|
+
try {
|
|
280
|
+
metadata = JSON.parse(fs.readFileSync(metaPath, 'utf-8'));
|
|
281
|
+
} catch (e) {}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
metadata['WORKFLOW_CATEGORY_INDEX'] = {
|
|
285
|
+
generatedAt: new Date().toISOString(),
|
|
286
|
+
itemCount: workflows.length
|
|
287
|
+
};
|
|
288
|
+
metadata['AGENT_CATEGORY_INDEX'] = {
|
|
289
|
+
generatedAt: new Date().toISOString(),
|
|
290
|
+
itemCount: agents.length
|
|
291
|
+
};
|
|
292
|
+
|
|
293
|
+
const metaDir = path.dirname(metaPath);
|
|
294
|
+
if (!fs.existsSync(metaDir)) {
|
|
295
|
+
fs.mkdirSync(metaDir, { recursive: true });
|
|
296
|
+
}
|
|
297
|
+
fs.writeFileSync(metaPath, JSON.stringify(metadata, null, 2));
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
return { success: true, results };
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// CLI execution
|
|
304
|
+
if (require.main === module) {
|
|
305
|
+
const args = process.argv.slice(2);
|
|
306
|
+
const dryRun = args.includes('--dry-run');
|
|
307
|
+
const verbose = args.includes('--verbose') || args.includes('-v');
|
|
308
|
+
|
|
309
|
+
const result = buildAll({ dryRun, verbose });
|
|
310
|
+
console.log(`\nIndex build ${result.success ? 'complete' : 'failed'}`);
|
|
311
|
+
process.exit(result.success ? 0 : 1);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
module.exports = {
|
|
315
|
+
buildAll,
|
|
316
|
+
scanWorkflows,
|
|
317
|
+
scanAgents,
|
|
318
|
+
scanCommands,
|
|
319
|
+
generateWorkflowIndex,
|
|
320
|
+
generateAgentIndex
|
|
321
|
+
};
|