pmp-gywd 3.3.0

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 (126) hide show
  1. package/LICENSE +27 -0
  2. package/README.md +567 -0
  3. package/bin/install.js +348 -0
  4. package/commands/gywd/add-phase.md +207 -0
  5. package/commands/gywd/anticipate.md +271 -0
  6. package/commands/gywd/bootstrap.md +336 -0
  7. package/commands/gywd/challenge.md +344 -0
  8. package/commands/gywd/check-drift.md +144 -0
  9. package/commands/gywd/complete-milestone.md +106 -0
  10. package/commands/gywd/consider-issues.md +202 -0
  11. package/commands/gywd/context.md +93 -0
  12. package/commands/gywd/create-roadmap.md +115 -0
  13. package/commands/gywd/deps.md +169 -0
  14. package/commands/gywd/digest.md +138 -0
  15. package/commands/gywd/discuss-milestone.md +47 -0
  16. package/commands/gywd/discuss-phase.md +60 -0
  17. package/commands/gywd/execute-plan.md +161 -0
  18. package/commands/gywd/extract-decisions.md +325 -0
  19. package/commands/gywd/health.md +150 -0
  20. package/commands/gywd/help.md +556 -0
  21. package/commands/gywd/history.md +278 -0
  22. package/commands/gywd/impact.md +317 -0
  23. package/commands/gywd/init.md +95 -0
  24. package/commands/gywd/insert-phase.md +227 -0
  25. package/commands/gywd/list-phase-assumptions.md +50 -0
  26. package/commands/gywd/map-codebase.md +84 -0
  27. package/commands/gywd/memory.md +159 -0
  28. package/commands/gywd/new-milestone.md +59 -0
  29. package/commands/gywd/new-project.md +315 -0
  30. package/commands/gywd/pause-work.md +123 -0
  31. package/commands/gywd/plan-fix.md +205 -0
  32. package/commands/gywd/plan-phase.md +93 -0
  33. package/commands/gywd/preview-plan.md +139 -0
  34. package/commands/gywd/profile.md +363 -0
  35. package/commands/gywd/progress.md +317 -0
  36. package/commands/gywd/remove-phase.md +338 -0
  37. package/commands/gywd/research-phase.md +91 -0
  38. package/commands/gywd/resume-work.md +40 -0
  39. package/commands/gywd/rollback.md +179 -0
  40. package/commands/gywd/status.md +42 -0
  41. package/commands/gywd/sync-github.md +234 -0
  42. package/commands/gywd/verify-work.md +71 -0
  43. package/commands/gywd/why.md +251 -0
  44. package/docs/COMMANDS.md +722 -0
  45. package/docs/CONTRIBUTING.md +342 -0
  46. package/docs/EXAMPLES.md +535 -0
  47. package/docs/GETTING-STARTED.md +262 -0
  48. package/docs/README.md +55 -0
  49. package/docs/RELEASING.md +159 -0
  50. package/get-your-work-done/core/agent-patterns.md +331 -0
  51. package/get-your-work-done/core/architecture.md +334 -0
  52. package/get-your-work-done/core/context-model-schema.json +154 -0
  53. package/get-your-work-done/core/decisions-schema.json +193 -0
  54. package/get-your-work-done/core/learning-state-schema.json +133 -0
  55. package/get-your-work-done/core/profile-schema.json +257 -0
  56. package/get-your-work-done/references/adaptive-decomposition.md +175 -0
  57. package/get-your-work-done/references/checkpoints.md +287 -0
  58. package/get-your-work-done/references/confidence-scoring.md +169 -0
  59. package/get-your-work-done/references/continuation-format.md +255 -0
  60. package/get-your-work-done/references/git-integration.md +254 -0
  61. package/get-your-work-done/references/plan-format.md +428 -0
  62. package/get-your-work-done/references/principles.md +157 -0
  63. package/get-your-work-done/references/questioning.md +162 -0
  64. package/get-your-work-done/references/research-pitfalls.md +215 -0
  65. package/get-your-work-done/references/scope-estimation.md +172 -0
  66. package/get-your-work-done/references/tdd.md +263 -0
  67. package/get-your-work-done/templates/codebase/architecture.md +255 -0
  68. package/get-your-work-done/templates/codebase/concerns.md +310 -0
  69. package/get-your-work-done/templates/codebase/conventions.md +307 -0
  70. package/get-your-work-done/templates/codebase/integrations.md +280 -0
  71. package/get-your-work-done/templates/codebase/stack.md +186 -0
  72. package/get-your-work-done/templates/codebase/structure.md +285 -0
  73. package/get-your-work-done/templates/codebase/testing.md +480 -0
  74. package/get-your-work-done/templates/config.json +18 -0
  75. package/get-your-work-done/templates/context.md +161 -0
  76. package/get-your-work-done/templates/continue-here.md +78 -0
  77. package/get-your-work-done/templates/discovery.md +146 -0
  78. package/get-your-work-done/templates/issues.md +32 -0
  79. package/get-your-work-done/templates/milestone-archive.md +123 -0
  80. package/get-your-work-done/templates/milestone-context.md +93 -0
  81. package/get-your-work-done/templates/milestone.md +115 -0
  82. package/get-your-work-done/templates/phase-prompt.md +303 -0
  83. package/get-your-work-done/templates/project.md +184 -0
  84. package/get-your-work-done/templates/research.md +529 -0
  85. package/get-your-work-done/templates/roadmap.md +196 -0
  86. package/get-your-work-done/templates/state.md +210 -0
  87. package/get-your-work-done/templates/summary.md +273 -0
  88. package/get-your-work-done/templates/uat-issues.md +143 -0
  89. package/get-your-work-done/workflows/complete-milestone.md +643 -0
  90. package/get-your-work-done/workflows/create-milestone.md +416 -0
  91. package/get-your-work-done/workflows/create-roadmap.md +481 -0
  92. package/get-your-work-done/workflows/discovery-phase.md +293 -0
  93. package/get-your-work-done/workflows/discuss-milestone.md +236 -0
  94. package/get-your-work-done/workflows/discuss-phase.md +247 -0
  95. package/get-your-work-done/workflows/execute-phase.md +1625 -0
  96. package/get-your-work-done/workflows/list-phase-assumptions.md +178 -0
  97. package/get-your-work-done/workflows/map-codebase.md +434 -0
  98. package/get-your-work-done/workflows/plan-phase.md +488 -0
  99. package/get-your-work-done/workflows/research-phase.md +436 -0
  100. package/get-your-work-done/workflows/resume-project.md +287 -0
  101. package/get-your-work-done/workflows/transition.md +580 -0
  102. package/get-your-work-done/workflows/verify-work.md +202 -0
  103. package/lib/automation/dependency-analyzer.js +635 -0
  104. package/lib/automation/doc-generator.js +643 -0
  105. package/lib/automation/index.js +42 -0
  106. package/lib/automation/test-generator.js +628 -0
  107. package/lib/context/context-analyzer.js +554 -0
  108. package/lib/context/context-cache.js +426 -0
  109. package/lib/context/context-predictor.js +622 -0
  110. package/lib/context/index.js +44 -0
  111. package/lib/memory/confidence-calibrator.js +484 -0
  112. package/lib/memory/feedback-collector.js +551 -0
  113. package/lib/memory/global-memory.js +465 -0
  114. package/lib/memory/index.js +75 -0
  115. package/lib/memory/pattern-aggregator.js +487 -0
  116. package/lib/memory/team-sync.js +501 -0
  117. package/lib/profile/index.js +24 -0
  118. package/lib/profile/pattern-learner.js +303 -0
  119. package/lib/profile/profile-manager.js +445 -0
  120. package/lib/questioning/index.js +49 -0
  121. package/lib/questioning/question-engine.js +311 -0
  122. package/lib/questioning/question-templates.js +315 -0
  123. package/lib/validators/command-validator.js +188 -0
  124. package/lib/validators/index.js +29 -0
  125. package/lib/validators/schema-validator.js +183 -0
  126. package/package.json +61 -0
@@ -0,0 +1,643 @@
1
+ /**
2
+ * Documentation Generator
3
+ *
4
+ * Automatically generates documentation from source code:
5
+ * - JSDoc comments extraction
6
+ * - API documentation
7
+ * - Module documentation
8
+ * - README generation
9
+ */
10
+
11
+ const fs = require('fs');
12
+ const path = require('path');
13
+
14
+ /**
15
+ * JSDoc tag patterns (reserved for future use)
16
+ */
17
+ const _JSDOC_PATTERNS = {
18
+ block: /\/\*\*\s*([\s\S]*?)\s*\*\//g,
19
+ param: /@param\s+\{([^}]+)\}\s+(\w+)(?:\s*-\s*(.+))?/g,
20
+ returns: /@returns?\s+\{([^}]+)\}(?:\s*-?\s*(.+))?/,
21
+ description: /^([^@]+)/,
22
+ example: /@example\s*([\s\S]*?)(?=@|$)/g,
23
+ throws: /@throws?\s+\{([^}]+)\}(?:\s*-?\s*(.+))?/g,
24
+ deprecated: /@deprecated(?:\s+(.+))?/,
25
+ since: /@since\s+(.+)/,
26
+ see: /@see\s+(.+)/g,
27
+ type: /@type\s+\{([^}]+)\}/,
28
+ typedef: /@typedef\s+\{([^}]+)\}\s+(\w+)/,
29
+ property: /@property\s+\{([^}]+)\}\s+(\w+)(?:\s*-\s*(.+))?/g,
30
+ private: /@private/,
31
+ public: /@public/,
32
+ static: /@static/,
33
+ async: /@async/,
34
+ class: /@class(?:\s+(\w+))?/,
35
+ constructor: /@constructor/,
36
+ module: /@module\s+(\w+)/,
37
+ memberof: /@memberof\s+(\w+)/,
38
+ };
39
+
40
+ /**
41
+ * Documentation types
42
+ */
43
+ const DOC_TYPES = {
44
+ MODULE: 'module',
45
+ CLASS: 'class',
46
+ FUNCTION: 'function',
47
+ METHOD: 'method',
48
+ PROPERTY: 'property',
49
+ CONSTANT: 'constant',
50
+ TYPEDEF: 'typedef',
51
+ };
52
+
53
+ /**
54
+ * Documentation Generator class
55
+ */
56
+ class DocGenerator {
57
+ constructor(options = {}) {
58
+ this.outputDir = options.outputDir || 'docs';
59
+ this.sourceDir = options.sourceDir || 'lib';
60
+ this.includePrivate = options.includePrivate || false;
61
+ this.format = options.format || 'markdown';
62
+ }
63
+
64
+ /**
65
+ * Parse JSDoc comments from file content
66
+ * @param {string} content - File content
67
+ * @returns {Array<object>}
68
+ */
69
+ parseJSDoc(content) {
70
+ const docs = [];
71
+ // Match JSDoc blocks followed by declarations
72
+ const blockPattern = '\\/\\*\\*\\s*([\\s\\S]*?)\\s*\\*\\/\\s*\\n?\\s*' +
73
+ '(?:export\\s+)?(?:async\\s+)?(?:(const|let|var|function|class)\\s+)?(\\w+)?';
74
+ const blockRegex = new RegExp(blockPattern, 'g');
75
+
76
+ let match;
77
+ while ((match = blockRegex.exec(content)) !== null) {
78
+ const commentBody = match[1];
79
+ const declType = match[2];
80
+ const name = match[3];
81
+
82
+ const doc = this.parseCommentBlock(commentBody);
83
+ doc.name = name || doc.name;
84
+ doc.declarationType = declType;
85
+
86
+ // Determine doc type
87
+ if (doc.class || declType === 'class') {
88
+ doc.type = DOC_TYPES.CLASS;
89
+ } else if (doc.typedef) {
90
+ doc.type = DOC_TYPES.TYPEDEF;
91
+ } else if (declType === 'function' || doc.params.length > 0 || doc.returns) {
92
+ doc.type = DOC_TYPES.FUNCTION;
93
+ } else if (doc.module) {
94
+ doc.type = DOC_TYPES.MODULE;
95
+ } else {
96
+ doc.type = DOC_TYPES.CONSTANT;
97
+ }
98
+
99
+ // Skip private unless configured
100
+ if (doc.private && !this.includePrivate) {
101
+ continue;
102
+ }
103
+
104
+ docs.push(doc);
105
+ }
106
+
107
+ return docs;
108
+ }
109
+
110
+ /**
111
+ * Parse a single JSDoc comment block
112
+ * @param {string} body - Comment body
113
+ * @returns {object}
114
+ */
115
+ parseCommentBlock(body) {
116
+ const lines = body
117
+ .split('\n')
118
+ .map(line => line.replace(/^\s*\*\s?/, '').trim())
119
+ .join('\n');
120
+
121
+ const doc = {
122
+ description: '',
123
+ params: [],
124
+ returns: null,
125
+ examples: [],
126
+ throws: [],
127
+ deprecated: null,
128
+ since: null,
129
+ see: [],
130
+ private: false,
131
+ static: false,
132
+ async: false,
133
+ properties: [],
134
+ };
135
+
136
+ // Extract description (text before first @tag)
137
+ const descMatch = lines.match(/^([^@]+)/);
138
+ if (descMatch) {
139
+ doc.description = descMatch[1].trim();
140
+ }
141
+
142
+ // Extract @param tags
143
+ const paramRegex = /@param\s+\{([^}]+)\}\s+(\[?\w+\]?)(?:\s*-?\s*(.+))?/g;
144
+ let paramMatch;
145
+ while ((paramMatch = paramRegex.exec(lines)) !== null) {
146
+ const paramName = paramMatch[2];
147
+ const optional = paramName.startsWith('[') && paramName.endsWith(']');
148
+ doc.params.push({
149
+ type: paramMatch[1],
150
+ name: paramName.replace(/[\[\]]/g, ''),
151
+ description: paramMatch[3] || '',
152
+ optional,
153
+ });
154
+ }
155
+
156
+ // Extract @returns
157
+ const returnsMatch = lines.match(/@returns?\s+\{([^}]+)\}(?:\s*-?\s*(.+))?/);
158
+ if (returnsMatch) {
159
+ doc.returns = {
160
+ type: returnsMatch[1],
161
+ description: returnsMatch[2] || '',
162
+ };
163
+ }
164
+
165
+ // Extract @example
166
+ const exampleRegex = /@example\s*([\s\S]*?)(?=@\w|$)/g;
167
+ let exampleMatch;
168
+ while ((exampleMatch = exampleRegex.exec(lines)) !== null) {
169
+ const example = exampleMatch[1].trim();
170
+ if (example) {
171
+ doc.examples.push(example);
172
+ }
173
+ }
174
+
175
+ // Extract @throws
176
+ const throwsRegex = /@throws?\s+\{([^}]+)\}(?:\s*-?\s*(.+))?/g;
177
+ let throwsMatch;
178
+ while ((throwsMatch = throwsRegex.exec(lines)) !== null) {
179
+ doc.throws.push({
180
+ type: throwsMatch[1],
181
+ description: throwsMatch[2] || '',
182
+ });
183
+ }
184
+
185
+ // Extract @property
186
+ const propRegex = /@property\s+\{([^}]+)\}\s+(\w+)(?:\s*-?\s*(.+))?/g;
187
+ let propMatch;
188
+ while ((propMatch = propRegex.exec(lines)) !== null) {
189
+ doc.properties.push({
190
+ type: propMatch[1],
191
+ name: propMatch[2],
192
+ description: propMatch[3] || '',
193
+ });
194
+ }
195
+
196
+ // Extract simple tags
197
+ const deprecatedMatch = lines.match(/@deprecated(?:\s+(.+))?/);
198
+ if (deprecatedMatch) {
199
+ doc.deprecated = deprecatedMatch[1] || true;
200
+ }
201
+
202
+ const sinceMatch = lines.match(/@since\s+(.+)/);
203
+ if (sinceMatch) {
204
+ doc.since = sinceMatch[1].trim();
205
+ }
206
+
207
+ const seeRegex = /@see\s+(.+)/g;
208
+ let seeMatch;
209
+ while ((seeMatch = seeRegex.exec(lines)) !== null) {
210
+ doc.see.push(seeMatch[1].trim());
211
+ }
212
+
213
+ const moduleMatch = lines.match(/@module\s+(\w+)/);
214
+ if (moduleMatch) {
215
+ doc.module = moduleMatch[1];
216
+ }
217
+
218
+ const classMatch = lines.match(/@class(?:\s+(\w+))?/);
219
+ if (classMatch) {
220
+ doc.class = classMatch[1] || true;
221
+ }
222
+
223
+ const typedefMatch = lines.match(/@typedef\s+\{([^}]+)\}\s+(\w+)/);
224
+ if (typedefMatch) {
225
+ doc.typedef = {
226
+ type: typedefMatch[1],
227
+ name: typedefMatch[2],
228
+ };
229
+ }
230
+
231
+ // Boolean flags
232
+ doc.private = /@private/.test(lines);
233
+ doc.static = /@static/.test(lines);
234
+ doc.async = /@async/.test(lines);
235
+
236
+ return doc;
237
+ }
238
+
239
+ /**
240
+ * Generate markdown documentation for a file
241
+ * @param {string} filePath - Source file path
242
+ * @returns {string}
243
+ */
244
+ generateMarkdown(filePath) {
245
+ let content;
246
+ try {
247
+ content = fs.readFileSync(filePath, 'utf-8');
248
+ } catch {
249
+ return `# Error\n\nCould not read file: ${filePath}`;
250
+ }
251
+
252
+ const docs = this.parseJSDoc(content);
253
+ const fileName = path.basename(filePath);
254
+ const moduleName = path.basename(filePath, path.extname(filePath));
255
+
256
+ const lines = [
257
+ `# ${moduleName}`,
258
+ '',
259
+ `Source: \`${fileName}\``,
260
+ '',
261
+ ];
262
+
263
+ // Find module-level description
264
+ const moduleDoc = docs.find(d => d.type === DOC_TYPES.MODULE);
265
+ if (moduleDoc) {
266
+ lines.push(moduleDoc.description, '');
267
+ }
268
+
269
+ // Group by type
270
+ const classes = docs.filter(d => d.type === DOC_TYPES.CLASS);
271
+ const functions = docs.filter(d => d.type === DOC_TYPES.FUNCTION);
272
+ const constants = docs.filter(d => d.type === DOC_TYPES.CONSTANT);
273
+ const typedefs = docs.filter(d => d.type === DOC_TYPES.TYPEDEF);
274
+
275
+ // Document typedefs
276
+ if (typedefs.length > 0) {
277
+ lines.push('## Type Definitions', '');
278
+ for (const typedef of typedefs) {
279
+ lines.push(...this.formatTypedef(typedef));
280
+ }
281
+ }
282
+
283
+ // Document classes
284
+ if (classes.length > 0) {
285
+ lines.push('## Classes', '');
286
+ for (const cls of classes) {
287
+ lines.push(...this.formatClass(cls, docs));
288
+ }
289
+ }
290
+
291
+ // Document functions
292
+ if (functions.length > 0) {
293
+ lines.push('## Functions', '');
294
+ for (const func of functions) {
295
+ lines.push(...this.formatFunction(func));
296
+ }
297
+ }
298
+
299
+ // Document constants
300
+ if (constants.length > 0) {
301
+ lines.push('## Constants', '');
302
+ for (const constant of constants) {
303
+ lines.push(...this.formatConstant(constant));
304
+ }
305
+ }
306
+
307
+ return lines.join('\n');
308
+ }
309
+
310
+ /**
311
+ * Format a function for markdown
312
+ * @param {object} doc - Function documentation
313
+ * @returns {string[]}
314
+ */
315
+ formatFunction(doc) {
316
+ const lines = [];
317
+ const asyncPrefix = doc.async ? 'async ' : '';
318
+ const params = doc.params.map(p => p.name).join(', ');
319
+
320
+ lines.push(`### ${asyncPrefix}${doc.name}(${params})`, '');
321
+
322
+ if (doc.deprecated) {
323
+ lines.push(`> **Deprecated**: ${doc.deprecated === true ? 'This function is deprecated.' : doc.deprecated}`, '');
324
+ }
325
+
326
+ if (doc.description) {
327
+ lines.push(doc.description, '');
328
+ }
329
+
330
+ if (doc.params.length > 0) {
331
+ lines.push('**Parameters:**', '');
332
+ lines.push('| Name | Type | Description |');
333
+ lines.push('|------|------|-------------|');
334
+ for (const param of doc.params) {
335
+ const optional = param.optional ? ' *(optional)*' : '';
336
+ lines.push(`| ${param.name}${optional} | \`${param.type}\` | ${param.description} |`);
337
+ }
338
+ lines.push('');
339
+ }
340
+
341
+ if (doc.returns) {
342
+ lines.push(`**Returns:** \`${doc.returns.type}\`${doc.returns.description ? ` - ${doc.returns.description}` : ''}`, '');
343
+ }
344
+
345
+ if (doc.throws.length > 0) {
346
+ lines.push('**Throws:**', '');
347
+ for (const t of doc.throws) {
348
+ lines.push(`- \`${t.type}\` - ${t.description}`);
349
+ }
350
+ lines.push('');
351
+ }
352
+
353
+ if (doc.examples.length > 0) {
354
+ lines.push('**Example:**', '');
355
+ for (const example of doc.examples) {
356
+ lines.push('```javascript', example, '```', '');
357
+ }
358
+ }
359
+
360
+ if (doc.since) {
361
+ lines.push(`*Since: ${doc.since}*`, '');
362
+ }
363
+
364
+ if (doc.see.length > 0) {
365
+ lines.push('**See also:**', '');
366
+ for (const see of doc.see) {
367
+ lines.push(`- ${see}`);
368
+ }
369
+ lines.push('');
370
+ }
371
+
372
+ lines.push('---', '');
373
+
374
+ return lines;
375
+ }
376
+
377
+ /**
378
+ * Format a class for markdown
379
+ * @param {object} doc - Class documentation
380
+ * @param {Array} allDocs - All documentation items
381
+ * @returns {string[]}
382
+ */
383
+ formatClass(doc, allDocs) {
384
+ const lines = [];
385
+
386
+ lines.push(`### class ${doc.name}`, '');
387
+
388
+ if (doc.deprecated) {
389
+ lines.push(`> **Deprecated**: ${doc.deprecated === true ? 'This class is deprecated.' : doc.deprecated}`, '');
390
+ }
391
+
392
+ if (doc.description) {
393
+ lines.push(doc.description, '');
394
+ }
395
+
396
+ // Find methods belonging to this class (reserved for future method documentation)
397
+ const _methods = allDocs.filter(d =>
398
+ d.memberof === doc.name ||
399
+ (d.type === DOC_TYPES.FUNCTION && d.name && d.name !== doc.name),
400
+ );
401
+
402
+ if (doc.properties.length > 0) {
403
+ lines.push('**Properties:**', '');
404
+ lines.push('| Name | Type | Description |');
405
+ lines.push('|------|------|-------------|');
406
+ for (const prop of doc.properties) {
407
+ lines.push(`| ${prop.name} | \`${prop.type}\` | ${prop.description} |`);
408
+ }
409
+ lines.push('');
410
+ }
411
+
412
+ if (doc.examples.length > 0) {
413
+ lines.push('**Example:**', '');
414
+ for (const example of doc.examples) {
415
+ lines.push('```javascript', example, '```', '');
416
+ }
417
+ }
418
+
419
+ lines.push('---', '');
420
+
421
+ return lines;
422
+ }
423
+
424
+ /**
425
+ * Format a constant for markdown
426
+ * @param {object} doc - Constant documentation
427
+ * @returns {string[]}
428
+ */
429
+ formatConstant(doc) {
430
+ const lines = [];
431
+
432
+ lines.push(`### ${doc.name}`, '');
433
+
434
+ if (doc.description) {
435
+ lines.push(doc.description, '');
436
+ }
437
+
438
+ if (doc.properties.length > 0) {
439
+ lines.push('**Properties:**', '');
440
+ lines.push('| Name | Type | Description |');
441
+ lines.push('|------|------|-------------|');
442
+ for (const prop of doc.properties) {
443
+ lines.push(`| ${prop.name} | \`${prop.type}\` | ${prop.description} |`);
444
+ }
445
+ lines.push('');
446
+ }
447
+
448
+ lines.push('---', '');
449
+
450
+ return lines;
451
+ }
452
+
453
+ /**
454
+ * Format a typedef for markdown
455
+ * @param {object} doc - Typedef documentation
456
+ * @returns {string[]}
457
+ */
458
+ formatTypedef(doc) {
459
+ const lines = [];
460
+ const name = doc.typedef?.name || doc.name;
461
+ const type = doc.typedef?.type || 'object';
462
+
463
+ lines.push(`### ${name}`, '');
464
+ lines.push(`Type: \`${type}\``, '');
465
+
466
+ if (doc.description) {
467
+ lines.push(doc.description, '');
468
+ }
469
+
470
+ if (doc.properties.length > 0) {
471
+ lines.push('**Properties:**', '');
472
+ lines.push('| Name | Type | Description |');
473
+ lines.push('|------|------|-------------|');
474
+ for (const prop of doc.properties) {
475
+ lines.push(`| ${prop.name} | \`${prop.type}\` | ${prop.description} |`);
476
+ }
477
+ lines.push('');
478
+ }
479
+
480
+ lines.push('---', '');
481
+
482
+ return lines;
483
+ }
484
+
485
+ /**
486
+ * Generate documentation for a directory
487
+ * @param {string} dir - Directory to document
488
+ * @param {boolean} dryRun - If true, don't write files
489
+ * @returns {Array}
490
+ */
491
+ generateForDirectory(dir, dryRun = false) {
492
+ const results = [];
493
+ const extensions = ['.js', '.ts', '.jsx', '.tsx', '.mjs'];
494
+
495
+ const scan = (scanDir) => {
496
+ let entries;
497
+ try {
498
+ entries = fs.readdirSync(scanDir, { withFileTypes: true });
499
+ } catch {
500
+ return;
501
+ }
502
+
503
+ for (const entry of entries) {
504
+ const fullPath = path.join(scanDir, entry.name);
505
+
506
+ if (entry.isDirectory()) {
507
+ if (!['node_modules', '.git', 'test', 'tests', '__tests__', 'docs'].includes(entry.name)) {
508
+ scan(fullPath);
509
+ }
510
+ } else if (entry.isFile()) {
511
+ const ext = path.extname(entry.name);
512
+ if (extensions.includes(ext)) {
513
+ const result = this.generateDocFile(fullPath, dryRun);
514
+ results.push(result);
515
+ }
516
+ }
517
+ }
518
+ };
519
+
520
+ scan(dir);
521
+ return results;
522
+ }
523
+
524
+ /**
525
+ * Generate documentation file for a source file
526
+ * @param {string} sourcePath - Source file path
527
+ * @param {boolean} dryRun - If true, don't write file
528
+ * @returns {object}
529
+ */
530
+ generateDocFile(sourcePath, dryRun = false) {
531
+ const content = this.generateMarkdown(sourcePath);
532
+ const docPath = this.getDocFilePath(sourcePath);
533
+
534
+ const result = {
535
+ source: sourcePath,
536
+ path: docPath,
537
+ content,
538
+ written: false,
539
+ };
540
+
541
+ if (!dryRun) {
542
+ const docDir = path.dirname(docPath);
543
+ if (!fs.existsSync(docDir)) {
544
+ fs.mkdirSync(docDir, { recursive: true });
545
+ }
546
+ fs.writeFileSync(docPath, content);
547
+ result.written = true;
548
+ }
549
+
550
+ return result;
551
+ }
552
+
553
+ /**
554
+ * Get documentation file path for a source file
555
+ * @param {string} sourcePath - Source file path
556
+ * @returns {string}
557
+ */
558
+ getDocFilePath(sourcePath) {
559
+ const baseName = path.basename(sourcePath, path.extname(sourcePath));
560
+ const sourceDir = path.dirname(sourcePath);
561
+ const relativeSrc = sourceDir.replace(this.sourceDir, '').replace(/^[/\\]/, '');
562
+
563
+ return path.join(this.outputDir, relativeSrc, `${baseName}.md`);
564
+ }
565
+
566
+ /**
567
+ * Generate API index file
568
+ * @param {string} dir - Directory to index
569
+ * @returns {string}
570
+ */
571
+ generateApiIndex(dir) {
572
+ const results = this.generateForDirectory(dir, true);
573
+ const lines = [
574
+ '# API Reference',
575
+ '',
576
+ `Generated: ${new Date().toISOString()}`,
577
+ '',
578
+ '## Modules',
579
+ '',
580
+ ];
581
+
582
+ // Group by directory
583
+ const byDir = new Map();
584
+ for (const result of results) {
585
+ const relPath = path.relative(dir, result.source);
586
+ const dirName = path.dirname(relPath) || 'root';
587
+
588
+ if (!byDir.has(dirName)) {
589
+ byDir.set(dirName, []);
590
+ }
591
+ byDir.get(dirName).push({
592
+ name: path.basename(result.source, path.extname(result.source)),
593
+ path: result.path,
594
+ });
595
+ }
596
+
597
+ for (const [dirName, files] of byDir) {
598
+ lines.push(`### ${dirName}`, '');
599
+ for (const file of files) {
600
+ const relDocPath = path.relative(this.outputDir, file.path);
601
+ lines.push(`- [${file.name}](${relDocPath})`);
602
+ }
603
+ lines.push('');
604
+ }
605
+
606
+ return lines.join('\n');
607
+ }
608
+
609
+ /**
610
+ * Generate full documentation
611
+ * @param {string} dir - Source directory
612
+ * @param {boolean} dryRun - If true, don't write files
613
+ * @returns {object}
614
+ */
615
+ generateAll(dir, dryRun = false) {
616
+ const moduleResults = this.generateForDirectory(dir, dryRun);
617
+ const indexContent = this.generateApiIndex(dir);
618
+
619
+ const results = {
620
+ modules: moduleResults,
621
+ index: {
622
+ path: path.join(this.outputDir, 'API.md'),
623
+ content: indexContent,
624
+ written: false,
625
+ },
626
+ };
627
+
628
+ if (!dryRun) {
629
+ if (!fs.existsSync(this.outputDir)) {
630
+ fs.mkdirSync(this.outputDir, { recursive: true });
631
+ }
632
+ fs.writeFileSync(results.index.path, indexContent);
633
+ results.index.written = true;
634
+ }
635
+
636
+ return results;
637
+ }
638
+ }
639
+
640
+ module.exports = {
641
+ DocGenerator,
642
+ DOC_TYPES,
643
+ };
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Automation Module
3
+ *
4
+ * Tools for automating development workflows:
5
+ * - Dependency analysis
6
+ * - Test generation
7
+ * - Documentation generation
8
+ */
9
+
10
+ const {
11
+ DependencyAnalyzer,
12
+ DEP_TYPES,
13
+ BUILTIN_MODULES,
14
+ } = require('./dependency-analyzer');
15
+
16
+ const {
17
+ TestGenerator,
18
+ TEST_FRAMEWORKS,
19
+ } = require('./test-generator');
20
+
21
+ const {
22
+ DocGenerator,
23
+ DOC_TYPES,
24
+ } = require('./doc-generator');
25
+
26
+ module.exports = {
27
+ // Classes
28
+ DependencyAnalyzer,
29
+ TestGenerator,
30
+ DocGenerator,
31
+
32
+ // Constants
33
+ DEP_TYPES,
34
+ BUILTIN_MODULES,
35
+ TEST_FRAMEWORKS,
36
+ DOC_TYPES,
37
+
38
+ // Factory functions
39
+ createDependencyAnalyzer: (options) => new DependencyAnalyzer(options),
40
+ createTestGenerator: (options) => new TestGenerator(options),
41
+ createDocGenerator: (options) => new DocGenerator(options),
42
+ };