aios-core 2.1.4 → 2.1.6

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.
Files changed (27) hide show
  1. package/.aios-core/development/tasks/analyze-brownfield.md +456 -456
  2. package/.aios-core/development/tasks/setup-project-docs.md +440 -444
  3. package/.aios-core/infrastructure/scripts/documentation-integrity/brownfield-analyzer.js +501 -501
  4. package/.aios-core/infrastructure/scripts/documentation-integrity/config-generator.js +368 -329
  5. package/.aios-core/infrastructure/scripts/documentation-integrity/deployment-config-loader.js +308 -282
  6. package/.aios-core/infrastructure/scripts/documentation-integrity/doc-generator.js +331 -331
  7. package/.aios-core/infrastructure/scripts/documentation-integrity/gitignore-generator.js +312 -312
  8. package/.aios-core/infrastructure/scripts/documentation-integrity/index.js +74 -74
  9. package/.aios-core/infrastructure/scripts/documentation-integrity/mode-detector.js +389 -358
  10. package/.aios-core/infrastructure/scripts/llm-routing/install-llm-routing.js +6 -6
  11. package/.aios-core/infrastructure/templates/core-config/core-config-brownfield.tmpl.yaml +176 -182
  12. package/.aios-core/infrastructure/templates/core-config/core-config-greenfield.tmpl.yaml +127 -127
  13. package/.aios-core/infrastructure/templates/project-docs/coding-standards-tmpl.md +346 -346
  14. package/.aios-core/infrastructure/templates/project-docs/source-tree-tmpl.md +177 -177
  15. package/.aios-core/infrastructure/templates/project-docs/tech-stack-tmpl.md +267 -267
  16. package/package.json +1 -1
  17. package/packages/installer/src/config/templates/env-template.js +2 -2
  18. package/packages/installer/src/wizard/wizard.js +1 -1
  19. package/packages/installer/tests/integration/environment-configuration.test.js +2 -1
  20. package/packages/installer/tests/unit/env-template.test.js +3 -2
  21. package/src/wizard/index.js +2 -2
  22. package/.aios-core/development/tasks/validate-structure.md +0 -243
  23. package/.aios-core/infrastructure/scripts/source-tree-guardian/index.js +0 -375
  24. package/.aios-core/infrastructure/scripts/source-tree-guardian/manifest-generator.js +0 -410
  25. package/.aios-core/infrastructure/scripts/source-tree-guardian/rules/naming-rules.yaml +0 -285
  26. package/.aios-core/infrastructure/scripts/source-tree-guardian/rules/placement-rules.yaml +0 -262
  27. package/.aios-core/infrastructure/scripts/source-tree-guardian/validator.js +0 -468
@@ -1,331 +1,331 @@
1
- /**
2
- * Documentation Generator Module
3
- *
4
- * Generates project-specific documentation from templates.
5
- * Supports Node.js, Python, Go, and Rust projects.
6
- *
7
- * @module documentation-integrity/doc-generator
8
- * @version 1.0.0
9
- * @story 6.9
10
- */
11
-
12
- const fs = require('fs');
13
- const path = require('path');
14
-
15
- // Template directory
16
- const TEMPLATES_DIR = path.join(__dirname, '..', '..', 'templates', 'project-docs');
17
-
18
- /**
19
- * Template file names
20
- * @enum {string}
21
- */
22
- const TemplateFiles = {
23
- SOURCE_TREE: 'source-tree-tmpl.md',
24
- CODING_STANDARDS: 'coding-standards-tmpl.md',
25
- TECH_STACK: 'tech-stack-tmpl.md',
26
- };
27
-
28
- /**
29
- * Output file names
30
- * @enum {string}
31
- */
32
- const OutputFiles = {
33
- SOURCE_TREE: 'source-tree.md',
34
- CODING_STANDARDS: 'coding-standards.md',
35
- TECH_STACK: 'tech-stack.md',
36
- };
37
-
38
- /**
39
- * Documentation context for template rendering
40
- * @typedef {Object} DocContext
41
- * @property {string} PROJECT_NAME - Project name
42
- * @property {string} GENERATED_DATE - Generation date
43
- * @property {string} INSTALLATION_MODE - Installation mode
44
- * @property {string} TECH_STACK - Detected tech stack
45
- * @property {boolean} IS_NODE - Is Node.js project
46
- * @property {boolean} IS_PYTHON - Is Python project
47
- * @property {boolean} IS_GO - Is Go project
48
- * @property {boolean} IS_RUST - Is Rust project
49
- * @property {boolean} IS_TYPESCRIPT - Uses TypeScript
50
- */
51
-
52
- /**
53
- * Builds documentation context from detected markers
54
- *
55
- * @param {string} projectName - Project name
56
- * @param {string} mode - Installation mode
57
- * @param {Object} markers - Detected project markers
58
- * @param {Object} [overrides] - Optional context overrides
59
- * @returns {DocContext} Documentation context
60
- */
61
- function buildDocContext(projectName, mode, markers, overrides = {}) {
62
- // Detect tech stack from markers
63
- const techStacks = [];
64
- if (markers.hasPackageJson) techStacks.push('Node.js');
65
- if (markers.hasPythonProject) techStacks.push('Python');
66
- if (markers.hasGoMod) techStacks.push('Go');
67
- if (markers.hasCargoToml) techStacks.push('Rust');
68
-
69
- // Determine file extension
70
- let fileExt = 'js';
71
- if (markers.hasTsconfig) fileExt = 'ts';
72
-
73
- // Build context
74
- const context = {
75
- // Basic info
76
- PROJECT_NAME: projectName,
77
- GENERATED_DATE: new Date().toISOString().split('T')[0],
78
- INSTALLATION_MODE: mode,
79
- TECH_STACK: techStacks.join(', ') || 'Unknown',
80
-
81
- // Language flags
82
- IS_NODE: markers.hasPackageJson || false,
83
- IS_PYTHON: markers.hasPythonProject || false,
84
- IS_GO: markers.hasGoMod || false,
85
- IS_RUST: markers.hasCargoToml || false,
86
- IS_TYPESCRIPT: markers.hasTsconfig || false,
87
-
88
- // Node.js specific
89
- FILE_EXT: fileExt,
90
- NODE_VERSION: '18+',
91
- TYPESCRIPT_VERSION: '5.0+',
92
- NPM_VERSION: '9+',
93
- SEMICOLONS: 'Required',
94
- SEMICOLONS_RULE: 'always',
95
- PRETTIER_SEMI: true,
96
-
97
- // Python specific
98
- PYTHON_PACKAGE_NAME: projectName.toLowerCase().replace(/[^a-z0-9]/g, '_'),
99
- PYTHON_VERSION: '3.11+',
100
- PYTHON_SHORT_VERSION: '311',
101
- POETRY_VERSION: '1.5+',
102
-
103
- // Go specific
104
- GO_VERSION: '1.21+',
105
- GO_MODULE: `github.com/user/${projectName}`,
106
-
107
- // Rust specific
108
- RUST_VERSION: '1.70+',
109
-
110
- // Deployment
111
- DEPLOYMENT_PLATFORM: null,
112
- PRODUCTION_BRANCH: 'main',
113
- STAGING_BRANCH: 'staging',
114
- HAS_STAGING: false,
115
-
116
- // Database
117
- DATABASE: null,
118
- CACHE: null,
119
-
120
- // Quality gates
121
- QUALITY_GATES: ['Lint', 'Type Check', 'Tests'],
122
-
123
- // Dependencies (to be populated by analyzer)
124
- DEPENDENCIES: [],
125
- DEV_DEPENDENCIES: [],
126
- ENV_VARS: [],
127
-
128
- // Apply overrides
129
- ...overrides,
130
- };
131
-
132
- return context;
133
- }
134
-
135
- /**
136
- * Simple template renderer with Handlebars-like syntax
137
- * Supports: {{variable}}, {{#if condition}}, {{/if}}, {{#each array}}, {{/each}}
138
- *
139
- * @param {string} template - Template string
140
- * @param {Object} context - Context object
141
- * @returns {string} Rendered template
142
- */
143
- function renderTemplate(template, context) {
144
- let result = template;
145
-
146
- // Process {{#if}} blocks
147
- result = processIfBlocks(result, context);
148
-
149
- // Process {{#each}} blocks
150
- result = processEachBlocks(result, context);
151
-
152
- // Replace simple variables {{variable}}
153
- result = result.replace(/\{\{([^#/}][^}]*)\}\}/g, (match, key) => {
154
- const value = getNestedValue(context, key.trim());
155
- return value !== undefined ? String(value) : match;
156
- });
157
-
158
- // Clean up empty lines from removed blocks
159
- result = result.replace(/\n{3,}/g, '\n\n');
160
-
161
- return result;
162
- }
163
-
164
- /**
165
- * Process {{#if condition}}...{{/if}} blocks
166
- *
167
- * @param {string} template - Template string
168
- * @param {Object} context - Context object
169
- * @returns {string} Processed template
170
- */
171
- function processIfBlocks(template, context) {
172
- // Match if blocks (non-greedy, innermost first)
173
- const ifRegex = /\{\{#if\s+(\w+)\}\}([\s\S]*?)\{\{\/if\}\}/g;
174
-
175
- let result = template;
176
- let iterations = 0;
177
- const maxIterations = 100; // Prevent infinite loops
178
-
179
- while (ifRegex.test(result) && iterations < maxIterations) {
180
- result = result.replace(ifRegex, (match, condition, content) => {
181
- const value = context[condition];
182
- if (value) {
183
- return content;
184
- }
185
- return '';
186
- });
187
- iterations++;
188
- }
189
-
190
- return result;
191
- }
192
-
193
- /**
194
- * Process {{#each array}}...{{/each}} blocks
195
- *
196
- * @param {string} template - Template string
197
- * @param {Object} context - Context object
198
- * @returns {string} Processed template
199
- */
200
- function processEachBlocks(template, context) {
201
- const eachRegex = /\{\{#each\s+(\w+)\}\}([\s\S]*?)\{\{\/each\}\}/g;
202
-
203
- return template.replace(eachRegex, (match, arrayName, content) => {
204
- const array = context[arrayName];
205
- if (!Array.isArray(array) || array.length === 0) {
206
- return '';
207
- }
208
-
209
- return array
210
- .map((item) => {
211
- let itemContent = content;
212
- if (typeof item === 'object') {
213
- // Replace {{this.property}} with item properties
214
- itemContent = itemContent.replace(/\{\{this\.(\w+)\}\}/g, (m, prop) => {
215
- return item[prop] !== undefined ? String(item[prop]) : m;
216
- });
217
- } else {
218
- // Replace {{this}} with item value
219
- itemContent = itemContent.replace(/\{\{this\}\}/g, String(item));
220
- }
221
- return itemContent;
222
- })
223
- .join('');
224
- });
225
- }
226
-
227
- /**
228
- * Get nested value from object using dot notation
229
- *
230
- * @param {Object} obj - Object to search
231
- * @param {string} path - Dot-notation path
232
- * @returns {*} Value at path or undefined
233
- */
234
- function getNestedValue(obj, path) {
235
- return path.split('.').reduce((current, key) => {
236
- return current && current[key] !== undefined ? current[key] : undefined;
237
- }, obj);
238
- }
239
-
240
- /**
241
- * Loads a template file
242
- *
243
- * @param {string} templateName - Template file name
244
- * @returns {string} Template content
245
- * @throws {Error} If template not found
246
- */
247
- function loadTemplate(templateName) {
248
- const templatePath = path.join(TEMPLATES_DIR, templateName);
249
-
250
- if (!fs.existsSync(templatePath)) {
251
- throw new Error(`Template not found: ${templatePath}`);
252
- }
253
-
254
- return fs.readFileSync(templatePath, 'utf8');
255
- }
256
-
257
- /**
258
- * Generates all documentation files for a project
259
- *
260
- * @param {string} targetDir - Target directory
261
- * @param {DocContext} context - Documentation context
262
- * @param {Object} [options] - Generation options
263
- * @param {boolean} [options.dryRun] - Don't write files, just return content
264
- * @returns {Object} Generated files with content
265
- */
266
- function generateDocs(targetDir, context, options = {}) {
267
- const docsDir = path.join(targetDir, 'docs', 'architecture');
268
- const results = {};
269
-
270
- // Ensure docs directory exists
271
- if (!options.dryRun) {
272
- fs.mkdirSync(docsDir, { recursive: true });
273
- }
274
-
275
- // Generate each doc
276
- const templates = [
277
- { template: TemplateFiles.SOURCE_TREE, output: OutputFiles.SOURCE_TREE },
278
- { template: TemplateFiles.CODING_STANDARDS, output: OutputFiles.CODING_STANDARDS },
279
- { template: TemplateFiles.TECH_STACK, output: OutputFiles.TECH_STACK },
280
- ];
281
-
282
- for (const { template, output } of templates) {
283
- try {
284
- const templateContent = loadTemplate(template);
285
- const rendered = renderTemplate(templateContent, context);
286
- const outputPath = path.join(docsDir, output);
287
-
288
- results[output] = {
289
- path: outputPath,
290
- content: rendered,
291
- success: true,
292
- };
293
-
294
- if (!options.dryRun) {
295
- fs.writeFileSync(outputPath, rendered, 'utf8');
296
- }
297
- } catch (error) {
298
- results[output] = {
299
- path: path.join(docsDir, output),
300
- content: null,
301
- success: false,
302
- error: error.message,
303
- };
304
- }
305
- }
306
-
307
- return results;
308
- }
309
-
310
- /**
311
- * Generates a single documentation file
312
- *
313
- * @param {string} templateName - Template file name
314
- * @param {DocContext} context - Documentation context
315
- * @returns {string} Rendered content
316
- */
317
- function generateDoc(templateName, context) {
318
- const template = loadTemplate(templateName);
319
- return renderTemplate(template, context);
320
- }
321
-
322
- module.exports = {
323
- buildDocContext,
324
- renderTemplate,
325
- loadTemplate,
326
- generateDocs,
327
- generateDoc,
328
- TemplateFiles,
329
- OutputFiles,
330
- TEMPLATES_DIR,
331
- };
1
+ /**
2
+ * Documentation Generator Module
3
+ *
4
+ * Generates project-specific documentation from templates.
5
+ * Supports Node.js, Python, Go, and Rust projects.
6
+ *
7
+ * @module documentation-integrity/doc-generator
8
+ * @version 1.0.0
9
+ * @story 6.9
10
+ */
11
+
12
+ const fs = require('fs');
13
+ const path = require('path');
14
+
15
+ // Template directory
16
+ const TEMPLATES_DIR = path.join(__dirname, '..', '..', 'templates', 'project-docs');
17
+
18
+ /**
19
+ * Template file names
20
+ * @enum {string}
21
+ */
22
+ const TemplateFiles = {
23
+ SOURCE_TREE: 'source-tree-tmpl.md',
24
+ CODING_STANDARDS: 'coding-standards-tmpl.md',
25
+ TECH_STACK: 'tech-stack-tmpl.md',
26
+ };
27
+
28
+ /**
29
+ * Output file names
30
+ * @enum {string}
31
+ */
32
+ const OutputFiles = {
33
+ SOURCE_TREE: 'source-tree.md',
34
+ CODING_STANDARDS: 'coding-standards.md',
35
+ TECH_STACK: 'tech-stack.md',
36
+ };
37
+
38
+ /**
39
+ * Documentation context for template rendering
40
+ * @typedef {Object} DocContext
41
+ * @property {string} PROJECT_NAME - Project name
42
+ * @property {string} GENERATED_DATE - Generation date
43
+ * @property {string} INSTALLATION_MODE - Installation mode
44
+ * @property {string} TECH_STACK - Detected tech stack
45
+ * @property {boolean} IS_NODE - Is Node.js project
46
+ * @property {boolean} IS_PYTHON - Is Python project
47
+ * @property {boolean} IS_GO - Is Go project
48
+ * @property {boolean} IS_RUST - Is Rust project
49
+ * @property {boolean} IS_TYPESCRIPT - Uses TypeScript
50
+ */
51
+
52
+ /**
53
+ * Builds documentation context from detected markers
54
+ *
55
+ * @param {string} projectName - Project name
56
+ * @param {string} mode - Installation mode
57
+ * @param {Object} markers - Detected project markers
58
+ * @param {Object} [overrides] - Optional context overrides
59
+ * @returns {DocContext} Documentation context
60
+ */
61
+ function buildDocContext(projectName, mode, markers, overrides = {}) {
62
+ // Detect tech stack from markers
63
+ const techStacks = [];
64
+ if (markers.hasPackageJson) techStacks.push('Node.js');
65
+ if (markers.hasPythonProject) techStacks.push('Python');
66
+ if (markers.hasGoMod) techStacks.push('Go');
67
+ if (markers.hasCargoToml) techStacks.push('Rust');
68
+
69
+ // Determine file extension
70
+ let fileExt = 'js';
71
+ if (markers.hasTsconfig) fileExt = 'ts';
72
+
73
+ // Build context
74
+ const context = {
75
+ // Basic info
76
+ PROJECT_NAME: projectName,
77
+ GENERATED_DATE: new Date().toISOString().split('T')[0],
78
+ INSTALLATION_MODE: mode,
79
+ TECH_STACK: techStacks.join(', ') || 'Unknown',
80
+
81
+ // Language flags
82
+ IS_NODE: markers.hasPackageJson || false,
83
+ IS_PYTHON: markers.hasPythonProject || false,
84
+ IS_GO: markers.hasGoMod || false,
85
+ IS_RUST: markers.hasCargoToml || false,
86
+ IS_TYPESCRIPT: markers.hasTsconfig || false,
87
+
88
+ // Node.js specific
89
+ FILE_EXT: fileExt,
90
+ NODE_VERSION: '18+',
91
+ TYPESCRIPT_VERSION: '5.0+',
92
+ NPM_VERSION: '9+',
93
+ SEMICOLONS: 'Required',
94
+ SEMICOLONS_RULE: 'always',
95
+ PRETTIER_SEMI: true,
96
+
97
+ // Python specific
98
+ PYTHON_PACKAGE_NAME: projectName.toLowerCase().replace(/[^a-z0-9]/g, '_'),
99
+ PYTHON_VERSION: '3.11+',
100
+ PYTHON_SHORT_VERSION: '311',
101
+ POETRY_VERSION: '1.5+',
102
+
103
+ // Go specific
104
+ GO_VERSION: '1.21+',
105
+ GO_MODULE: `github.com/user/${projectName}`,
106
+
107
+ // Rust specific
108
+ RUST_VERSION: '1.70+',
109
+
110
+ // Deployment
111
+ DEPLOYMENT_PLATFORM: null,
112
+ PRODUCTION_BRANCH: 'main',
113
+ STAGING_BRANCH: 'staging',
114
+ HAS_STAGING: false,
115
+
116
+ // Database
117
+ DATABASE: null,
118
+ CACHE: null,
119
+
120
+ // Quality gates
121
+ QUALITY_GATES: ['Lint', 'Type Check', 'Tests'],
122
+
123
+ // Dependencies (to be populated by analyzer)
124
+ DEPENDENCIES: [],
125
+ DEV_DEPENDENCIES: [],
126
+ ENV_VARS: [],
127
+
128
+ // Apply overrides
129
+ ...overrides,
130
+ };
131
+
132
+ return context;
133
+ }
134
+
135
+ /**
136
+ * Simple template renderer with Handlebars-like syntax
137
+ * Supports: {{variable}}, {{#if condition}}, {{/if}}, {{#each array}}, {{/each}}
138
+ *
139
+ * @param {string} template - Template string
140
+ * @param {Object} context - Context object
141
+ * @returns {string} Rendered template
142
+ */
143
+ function renderTemplate(template, context) {
144
+ let result = template;
145
+
146
+ // Process {{#if}} blocks
147
+ result = processIfBlocks(result, context);
148
+
149
+ // Process {{#each}} blocks
150
+ result = processEachBlocks(result, context);
151
+
152
+ // Replace simple variables {{variable}}
153
+ result = result.replace(/\{\{([^#/}][^}]*)\}\}/g, (match, key) => {
154
+ const value = getNestedValue(context, key.trim());
155
+ return value !== undefined ? String(value) : match;
156
+ });
157
+
158
+ // Clean up empty lines from removed blocks
159
+ result = result.replace(/\n{3,}/g, '\n\n');
160
+
161
+ return result;
162
+ }
163
+
164
+ /**
165
+ * Process {{#if condition}}...{{/if}} blocks
166
+ *
167
+ * @param {string} template - Template string
168
+ * @param {Object} context - Context object
169
+ * @returns {string} Processed template
170
+ */
171
+ function processIfBlocks(template, context) {
172
+ // Match if blocks (non-greedy, innermost first)
173
+ const ifRegex = /\{\{#if\s+(\w+)\}\}([\s\S]*?)\{\{\/if\}\}/g;
174
+
175
+ let result = template;
176
+ let iterations = 0;
177
+ const maxIterations = 100; // Prevent infinite loops
178
+
179
+ while (ifRegex.test(result) && iterations < maxIterations) {
180
+ result = result.replace(ifRegex, (match, condition, content) => {
181
+ const value = context[condition];
182
+ if (value) {
183
+ return content;
184
+ }
185
+ return '';
186
+ });
187
+ iterations++;
188
+ }
189
+
190
+ return result;
191
+ }
192
+
193
+ /**
194
+ * Process {{#each array}}...{{/each}} blocks
195
+ *
196
+ * @param {string} template - Template string
197
+ * @param {Object} context - Context object
198
+ * @returns {string} Processed template
199
+ */
200
+ function processEachBlocks(template, context) {
201
+ const eachRegex = /\{\{#each\s+(\w+)\}\}([\s\S]*?)\{\{\/each\}\}/g;
202
+
203
+ return template.replace(eachRegex, (match, arrayName, content) => {
204
+ const array = context[arrayName];
205
+ if (!Array.isArray(array) || array.length === 0) {
206
+ return '';
207
+ }
208
+
209
+ return array
210
+ .map((item) => {
211
+ let itemContent = content;
212
+ if (typeof item === 'object') {
213
+ // Replace {{this.property}} with item properties
214
+ itemContent = itemContent.replace(/\{\{this\.(\w+)\}\}/g, (m, prop) => {
215
+ return item[prop] !== undefined ? String(item[prop]) : m;
216
+ });
217
+ } else {
218
+ // Replace {{this}} with item value
219
+ itemContent = itemContent.replace(/\{\{this\}\}/g, String(item));
220
+ }
221
+ return itemContent;
222
+ })
223
+ .join('');
224
+ });
225
+ }
226
+
227
+ /**
228
+ * Get nested value from object using dot notation
229
+ *
230
+ * @param {Object} obj - Object to search
231
+ * @param {string} path - Dot-notation path
232
+ * @returns {*} Value at path or undefined
233
+ */
234
+ function getNestedValue(obj, path) {
235
+ return path.split('.').reduce((current, key) => {
236
+ return current && current[key] !== undefined ? current[key] : undefined;
237
+ }, obj);
238
+ }
239
+
240
+ /**
241
+ * Loads a template file
242
+ *
243
+ * @param {string} templateName - Template file name
244
+ * @returns {string} Template content
245
+ * @throws {Error} If template not found
246
+ */
247
+ function loadTemplate(templateName) {
248
+ const templatePath = path.join(TEMPLATES_DIR, templateName);
249
+
250
+ if (!fs.existsSync(templatePath)) {
251
+ throw new Error(`Template not found: ${templatePath}`);
252
+ }
253
+
254
+ return fs.readFileSync(templatePath, 'utf8');
255
+ }
256
+
257
+ /**
258
+ * Generates all documentation files for a project
259
+ *
260
+ * @param {string} targetDir - Target directory
261
+ * @param {DocContext} context - Documentation context
262
+ * @param {Object} [options] - Generation options
263
+ * @param {boolean} [options.dryRun] - Don't write files, just return content
264
+ * @returns {Object} Generated files with content
265
+ */
266
+ function generateDocs(targetDir, context, options = {}) {
267
+ const docsDir = path.join(targetDir, 'docs', 'architecture');
268
+ const results = {};
269
+
270
+ // Ensure docs directory exists
271
+ if (!options.dryRun) {
272
+ fs.mkdirSync(docsDir, { recursive: true });
273
+ }
274
+
275
+ // Generate each doc
276
+ const templates = [
277
+ { template: TemplateFiles.SOURCE_TREE, output: OutputFiles.SOURCE_TREE },
278
+ { template: TemplateFiles.CODING_STANDARDS, output: OutputFiles.CODING_STANDARDS },
279
+ { template: TemplateFiles.TECH_STACK, output: OutputFiles.TECH_STACK },
280
+ ];
281
+
282
+ for (const { template, output } of templates) {
283
+ try {
284
+ const templateContent = loadTemplate(template);
285
+ const rendered = renderTemplate(templateContent, context);
286
+ const outputPath = path.join(docsDir, output);
287
+
288
+ results[output] = {
289
+ path: outputPath,
290
+ content: rendered,
291
+ success: true,
292
+ };
293
+
294
+ if (!options.dryRun) {
295
+ fs.writeFileSync(outputPath, rendered, 'utf8');
296
+ }
297
+ } catch (error) {
298
+ results[output] = {
299
+ path: path.join(docsDir, output),
300
+ content: null,
301
+ success: false,
302
+ error: error.message,
303
+ };
304
+ }
305
+ }
306
+
307
+ return results;
308
+ }
309
+
310
+ /**
311
+ * Generates a single documentation file
312
+ *
313
+ * @param {string} templateName - Template file name
314
+ * @param {DocContext} context - Documentation context
315
+ * @returns {string} Rendered content
316
+ */
317
+ function generateDoc(templateName, context) {
318
+ const template = loadTemplate(templateName);
319
+ return renderTemplate(template, context);
320
+ }
321
+
322
+ module.exports = {
323
+ buildDocContext,
324
+ renderTemplate,
325
+ loadTemplate,
326
+ generateDocs,
327
+ generateDoc,
328
+ TemplateFiles,
329
+ OutputFiles,
330
+ TEMPLATES_DIR,
331
+ };