create-universal-ai-context 2.1.0 → 2.1.2

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,7 +1,7 @@
1
1
  /**
2
2
  * Claude Adapter
3
3
  *
4
- * Generates AI_CONTEXT.md and .ai-context/ directory structure.
4
+ * Generates AI_CONTEXT.md and .claude/ directory structure.
5
5
  * This is the primary/universal format.
6
6
  */
7
7
 
@@ -16,8 +16,8 @@ const adapter = {
16
16
  name: 'claude',
17
17
  displayName: 'Claude Code',
18
18
  description: 'Universal AI context format for Claude Code and other AI assistants',
19
- outputType: 'single-file',
20
- outputPath: 'AI_CONTEXT.md'
19
+ outputType: 'multi-file',
20
+ outputPath: '.claude/'
21
21
  };
22
22
 
23
23
  /**
@@ -35,11 +35,13 @@ function getOutputPath(projectRoot) {
35
35
  * @returns {boolean}
36
36
  */
37
37
  function exists(projectRoot) {
38
- return fs.existsSync(getOutputPath(projectRoot));
38
+ const aiContextPath = getOutputPath(projectRoot);
39
+ const claudeDir = path.join(projectRoot, '.claude');
40
+ return fs.existsSync(aiContextPath) || fs.existsSync(claudeDir);
39
41
  }
40
42
 
41
43
  /**
42
- * Generate Claude context file
44
+ * Generate Claude context file and .claude/ directory structure
43
45
  * @param {object} analysis - Analysis results from static analyzer
44
46
  * @param {object} config - Configuration from CLI
45
47
  * @param {string} projectRoot - Project root directory
@@ -54,22 +56,24 @@ async function generate(analysis, config, projectRoot) {
54
56
  };
55
57
 
56
58
  try {
57
- // Build context from analysis
59
+ // 1. Generate AI_CONTEXT.md at project root (existing behavior)
58
60
  const context = buildContext(analysis, config);
59
-
60
- // Render template
61
61
  const content = renderTemplateByName('claude', context);
62
-
63
- // Write output file
64
62
  const outputPath = getOutputPath(projectRoot);
65
63
  fs.writeFileSync(outputPath, content, 'utf-8');
66
-
67
- result.success = true;
68
64
  result.files.push({
69
65
  path: outputPath,
70
66
  relativePath: 'AI_CONTEXT.md',
71
67
  size: content.length
72
68
  });
69
+
70
+ // 2. Generate .claude/ directory structure (NEW)
71
+ const claudeDirResult = await generateClaudeDirectory(projectRoot, context, result);
72
+ if (claudeDirResult) {
73
+ result.files.push(...claudeDirResult);
74
+ }
75
+
76
+ result.success = result.errors.length === 0 || result.errors.some(e => e.code === 'EXISTS');
73
77
  } catch (error) {
74
78
  result.errors.push({
75
79
  message: error.message,
@@ -80,36 +84,183 @@ async function generate(analysis, config, projectRoot) {
80
84
  return result;
81
85
  }
82
86
 
87
+ /**
88
+ * Generate .claude/ directory with full structure
89
+ * @param {string} projectRoot - Project root directory
90
+ * @param {object} context - Template context
91
+ * @param {object} result - Result object to track files/errors
92
+ * @returns {Array} List of generated files
93
+ */
94
+ async function generateClaudeDirectory(projectRoot, context, result) {
95
+ const { copyDirectory } = require('../installer');
96
+ const templatesDir = path.join(__dirname, '..', '..', 'templates', 'base');
97
+ const claudeDir = path.join(projectRoot, '.claude');
98
+
99
+ // Don't overwrite existing .claude/ directory
100
+ if (fs.existsSync(claudeDir)) {
101
+ result.errors.push({
102
+ message: '.claude/ directory already exists, skipping structure generation',
103
+ code: 'EXISTS',
104
+ severity: 'warning'
105
+ });
106
+ return [{
107
+ path: claudeDir,
108
+ relativePath: '.claude/',
109
+ size: 0,
110
+ skipped: true
111
+ }];
112
+ }
113
+
114
+ try {
115
+ // Create .claude/ directory
116
+ fs.mkdirSync(claudeDir, { recursive: true });
117
+
118
+ // Copy relevant subdirectories from templates/base to .claude/
119
+ const subdirsToCopy = [
120
+ 'agents',
121
+ 'commands',
122
+ 'indexes',
123
+ 'context',
124
+ 'schemas',
125
+ 'standards'
126
+ ];
127
+
128
+ // Only copy tools if explicitly enabled
129
+ if (context.features?.tools !== false) {
130
+ subdirsToCopy.push('tools');
131
+ }
132
+
133
+ let filesCopied = 0;
134
+ for (const subdir of subdirsToCopy) {
135
+ const srcPath = path.join(templatesDir, subdir);
136
+ if (fs.existsSync(srcPath)) {
137
+ const destPath = path.join(claudeDir, subdir);
138
+ fs.mkdirSync(destPath, { recursive: true });
139
+ const count = await copyDirectory(srcPath, destPath);
140
+ filesCopied += count;
141
+ }
142
+ }
143
+
144
+ // Create minimal .claude/settings.json
145
+ const settingsPath = path.join(claudeDir, 'settings.json');
146
+ const settings = {
147
+ '$schema': './schemas/settings.schema.json',
148
+ version: '2.1.0',
149
+ project: {
150
+ name: context.project?.name || 'Project',
151
+ tech_stack: context.project?.tech_stack || 'Not detected'
152
+ },
153
+ agents: {
154
+ context_engineer: 'enabled',
155
+ core_architect: 'enabled',
156
+ api_developer: 'enabled',
157
+ database_ops: 'enabled',
158
+ integration_hub: 'enabled',
159
+ deployment_ops: 'enabled'
160
+ },
161
+ commands: {
162
+ rpi_workflow: 'enabled',
163
+ validation: 'enabled'
164
+ }
165
+ };
166
+ fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
167
+ filesCopied++;
168
+
169
+ // Create .claude/README.md
170
+ const readmePath = path.join(claudeDir, 'README.md');
171
+ const readme = `# .claude Configuration - ${context.project?.name || 'Project'}
172
+
173
+ This directory contains Claude Code-specific context engineering files.
174
+
175
+ ## Quick Start
176
+
177
+ 1. Load agents: \`@context-engineer\`
178
+ 2. Use commands: \`/rpi-research\`, \`/rpi-plan\`, \`/rpi-implement\`
179
+ 3. Validate: \`/verify-docs-current\`
180
+
181
+ ## Universal Context
182
+
183
+ See \`AI_CONTEXT.md\` at project root for universal AI context (works with all tools).
184
+
185
+ ## Claude-Specific Files
186
+
187
+ - **agents/** - Specialized agents for different tasks
188
+ - **commands/** - Custom slash commands
189
+ - **indexes/** - 3-level navigation system
190
+ - **context/** - Workflow documentation
191
+
192
+ *Generated by create-universal-ai-context v${context.version || '2.1.0'}*
193
+ `;
194
+ fs.writeFileSync(readmePath, readme);
195
+ filesCopied++;
196
+
197
+ return [{
198
+ path: claudeDir,
199
+ relativePath: '.claude/',
200
+ size: filesCopied
201
+ }];
202
+
203
+ } catch (error) {
204
+ result.errors.push({
205
+ message: `Failed to generate .claude/ directory: ${error.message}`,
206
+ stack: error.stack
207
+ });
208
+ return null;
209
+ }
210
+ }
211
+
83
212
  /**
84
213
  * Validate Claude output
85
214
  * @param {string} projectRoot - Project root directory
86
215
  * @returns {object} Validation result
87
216
  */
88
217
  function validate(projectRoot) {
89
- const outputPath = getOutputPath(projectRoot);
218
+ const issues = [];
90
219
 
220
+ // 1. Validate AI_CONTEXT.md
221
+ const outputPath = getOutputPath(projectRoot);
91
222
  if (!fs.existsSync(outputPath)) {
92
- return {
93
- valid: false,
94
- error: 'AI_CONTEXT.md not found'
95
- };
223
+ issues.push({ file: 'AI_CONTEXT.md', error: 'not found' });
224
+ } else {
225
+ const content = fs.readFileSync(outputPath, 'utf-8');
226
+ const placeholderMatch = content.match(/\{\{[A-Z_]+\}\}/g);
227
+ if (placeholderMatch && placeholderMatch.length > 0) {
228
+ issues.push({
229
+ file: 'AI_CONTEXT.md',
230
+ error: `Found ${placeholderMatch.length} unreplaced placeholders`
231
+ });
232
+ }
96
233
  }
97
234
 
98
- const content = fs.readFileSync(outputPath, 'utf-8');
99
-
100
- // Check for unreplaced placeholders
101
- const placeholderMatch = content.match(/\{\{[A-Z_]+\}\}/g);
102
- if (placeholderMatch && placeholderMatch.length > 0) {
103
- return {
104
- valid: false,
105
- error: `Found ${placeholderMatch.length} unreplaced placeholders`,
106
- placeholders: placeholderMatch
107
- };
235
+ // 2. Validate .claude/ directory (optional, warn if missing)
236
+ const claudeDir = path.join(projectRoot, '.claude');
237
+ if (!fs.existsSync(claudeDir)) {
238
+ issues.push({
239
+ file: '.claude/',
240
+ error: 'directory not found (optional but recommended)',
241
+ severity: 'warning'
242
+ });
243
+ } else {
244
+ // Check for critical files
245
+ const criticalFiles = [
246
+ 'settings.json',
247
+ 'README.md'
248
+ ];
249
+ for (const file of criticalFiles) {
250
+ if (!fs.existsSync(path.join(claudeDir, file))) {
251
+ issues.push({
252
+ file: `.claude/${file}`,
253
+ error: 'missing',
254
+ severity: 'warning'
255
+ });
256
+ }
257
+ }
108
258
  }
109
259
 
110
260
  return {
111
- valid: true,
112
- size: content.length
261
+ valid: issues.filter(i => i.severity !== 'warning').length === 0,
262
+ issues,
263
+ warnings: issues.filter(i => i.severity === 'warning').length
113
264
  };
114
265
  }
115
266
 
package/lib/installer.js CHANGED
@@ -415,4 +415,5 @@ module.exports = {
415
415
  DIRECTORY_STRUCTURE,
416
416
  AI_CONTEXT_DIR,
417
417
  AI_CONTEXT_FILE,
418
+ copyDirectory, // Export for use by adapters
418
419
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-universal-ai-context",
3
- "version": "2.1.0",
3
+ "version": "2.1.2",
4
4
  "description": "Universal AI Context Engineering - Set up context for Claude, Copilot, Cline, Antigravity, and more",
5
5
  "main": "lib/index.js",
6
6
  "bin": {