agentsys 5.0.3 → 5.1.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.
- package/.claude-plugin/marketplace.json +21 -14
- package/.claude-plugin/plugin.json +1 -1
- package/AGENTS.md +2 -1
- package/CHANGELOG.md +18 -0
- package/README.md +7 -6
- package/adapters/codex/skills/agnix/SKILL.md +0 -1
- package/adapters/codex/skills/audit-project/SKILL.md +0 -1
- package/adapters/codex/skills/audit-project-agents/SKILL.md +0 -1
- package/adapters/codex/skills/audit-project-github/SKILL.md +0 -1
- package/adapters/codex/skills/consult/SKILL.md +132 -57
- package/adapters/codex/skills/debate/SKILL.md +214 -0
- package/adapters/codex/skills/delivery-approval/SKILL.md +0 -1
- package/adapters/codex/skills/deslop/SKILL.md +0 -1
- package/adapters/codex/skills/drift-detect/SKILL.md +0 -1
- package/adapters/codex/skills/enhance/SKILL.md +0 -1
- package/adapters/codex/skills/learn/SKILL.md +0 -1
- package/adapters/codex/skills/next-task/SKILL.md +0 -1
- package/adapters/codex/skills/perf/SKILL.md +0 -1
- package/adapters/codex/skills/repo-map/SKILL.md +0 -1
- package/adapters/codex/skills/ship/SKILL.md +0 -1
- package/adapters/codex/skills/ship-ci-review-loop/SKILL.md +0 -1
- package/adapters/codex/skills/ship-deployment/SKILL.md +0 -1
- package/adapters/codex/skills/ship-error-handling/SKILL.md +0 -1
- package/adapters/codex/skills/sync-docs/SKILL.md +0 -1
- package/adapters/opencode/agents/agent-enhancer.md +0 -1
- package/adapters/opencode/agents/agnix-agent.md +0 -1
- package/adapters/opencode/agents/ci-fixer.md +0 -1
- package/adapters/opencode/agents/ci-monitor.md +0 -1
- package/adapters/opencode/agents/claudemd-enhancer.md +0 -1
- package/adapters/opencode/agents/consult-agent.md +122 -30
- package/adapters/opencode/agents/cross-file-enhancer.md +0 -1
- package/adapters/opencode/agents/debate-orchestrator.md +169 -0
- package/adapters/opencode/agents/delivery-validator.md +0 -1
- package/adapters/opencode/agents/deslop-agent.md +0 -1
- package/adapters/opencode/agents/docs-enhancer.md +0 -1
- package/adapters/opencode/agents/exploration-agent.md +0 -1
- package/adapters/opencode/agents/hooks-enhancer.md +0 -1
- package/adapters/opencode/agents/implementation-agent.md +0 -1
- package/adapters/opencode/agents/learn-agent.md +0 -1
- package/adapters/opencode/agents/map-validator.md +0 -1
- package/adapters/opencode/agents/perf-analyzer.md +0 -1
- package/adapters/opencode/agents/perf-code-paths.md +0 -1
- package/adapters/opencode/agents/perf-investigation-logger.md +0 -1
- package/adapters/opencode/agents/perf-orchestrator.md +0 -1
- package/adapters/opencode/agents/perf-theory-gatherer.md +0 -1
- package/adapters/opencode/agents/perf-theory-tester.md +0 -1
- package/adapters/opencode/agents/plan-synthesizer.md +0 -1
- package/adapters/opencode/agents/planning-agent.md +0 -1
- package/adapters/opencode/agents/plugin-enhancer.md +0 -1
- package/adapters/opencode/agents/prompt-enhancer.md +0 -1
- package/adapters/opencode/agents/simple-fixer.md +0 -1
- package/adapters/opencode/agents/skills-enhancer.md +0 -1
- package/adapters/opencode/agents/sync-docs-agent.md +0 -1
- package/adapters/opencode/agents/task-discoverer.md +0 -1
- package/adapters/opencode/agents/test-coverage-checker.md +0 -1
- package/adapters/opencode/agents/worktree-manager.md +0 -1
- package/adapters/opencode/commands/agnix.md +0 -1
- package/adapters/opencode/commands/audit-project-agents.md +0 -1
- package/adapters/opencode/commands/audit-project-github.md +0 -1
- package/adapters/opencode/commands/audit-project.md +0 -1
- package/adapters/opencode/commands/consult.md +133 -57
- package/adapters/opencode/commands/debate.md +224 -0
- package/adapters/opencode/commands/delivery-approval.md +0 -1
- package/adapters/opencode/commands/deslop.md +0 -1
- package/adapters/opencode/commands/drift-detect.md +0 -1
- package/adapters/opencode/commands/enhance.md +0 -1
- package/adapters/opencode/commands/learn.md +0 -1
- package/adapters/opencode/commands/next-task.md +0 -1
- package/adapters/opencode/commands/perf.md +0 -1
- package/adapters/opencode/commands/repo-map.md +0 -1
- package/adapters/opencode/commands/ship-ci-review-loop.md +0 -1
- package/adapters/opencode/commands/ship-deployment.md +0 -1
- package/adapters/opencode/commands/ship-error-handling.md +0 -1
- package/adapters/opencode/commands/ship.md +0 -1
- package/adapters/opencode/commands/sync-docs.md +0 -1
- package/adapters/opencode/skills/agnix/SKILL.md +1 -2
- package/adapters/opencode/skills/consult/SKILL.md +33 -23
- package/adapters/opencode/skills/debate/SKILL.md +245 -0
- package/adapters/opencode/skills/deslop/SKILL.md +1 -2
- package/adapters/opencode/skills/discover-tasks/SKILL.md +1 -2
- package/adapters/opencode/skills/drift-analysis/SKILL.md +1 -2
- package/adapters/opencode/skills/enhance-agent-prompts/SKILL.md +1 -2
- package/adapters/opencode/skills/enhance-claude-memory/SKILL.md +1 -2
- package/adapters/opencode/skills/enhance-cross-file/SKILL.md +1 -2
- package/adapters/opencode/skills/enhance-docs/SKILL.md +1 -2
- package/adapters/opencode/skills/enhance-hooks/SKILL.md +1 -2
- package/adapters/opencode/skills/enhance-orchestrator/SKILL.md +1 -2
- package/adapters/opencode/skills/enhance-plugins/SKILL.md +1 -2
- package/adapters/opencode/skills/enhance-prompts/SKILL.md +1 -2
- package/adapters/opencode/skills/enhance-skills/SKILL.md +1 -2
- package/adapters/opencode/skills/learn/SKILL.md +1 -2
- package/adapters/opencode/skills/orchestrate-review/SKILL.md +0 -1
- package/adapters/opencode/skills/perf-analyzer/SKILL.md +1 -2
- package/adapters/opencode/skills/perf-baseline-manager/SKILL.md +1 -2
- package/adapters/opencode/skills/perf-benchmarker/SKILL.md +1 -2
- package/adapters/opencode/skills/perf-code-paths/SKILL.md +1 -2
- package/adapters/opencode/skills/perf-investigation-logger/SKILL.md +1 -2
- package/adapters/opencode/skills/perf-profiler/SKILL.md +1 -2
- package/adapters/opencode/skills/perf-theory-gatherer/SKILL.md +1 -2
- package/adapters/opencode/skills/perf-theory-tester/SKILL.md +1 -2
- package/adapters/opencode/skills/repo-mapping/SKILL.md +1 -2
- package/adapters/opencode/skills/sync-docs/SKILL.md +1 -2
- package/adapters/opencode/skills/validate-delivery/SKILL.md +1 -2
- package/lib/adapter-transforms.js +24 -4
- package/package.json +1 -1
- package/plugins/agnix/.claude-plugin/plugin.json +1 -1
- package/plugins/agnix/skills/agnix/SKILL.md +1 -1
- package/plugins/audit-project/.claude-plugin/plugin.json +1 -1
- package/plugins/audit-project/lib/adapter-transforms.js +24 -4
- package/plugins/consult/.claude-plugin/plugin.json +1 -1
- package/plugins/consult/agents/consult-agent.md +122 -29
- package/plugins/consult/commands/consult.md +135 -58
- package/plugins/consult/skills/consult/SKILL.md +31 -20
- package/plugins/debate/.claude-plugin/plugin.json +21 -0
- package/plugins/debate/agents/debate-orchestrator.md +175 -0
- package/plugins/debate/commands/debate.md +221 -0
- package/plugins/debate/lib/adapter-transforms.js +298 -0
- package/plugins/debate/lib/collectors/codebase.js +392 -0
- package/plugins/debate/lib/collectors/docs-patterns.js +713 -0
- package/plugins/debate/lib/collectors/documentation.js +219 -0
- package/plugins/debate/lib/collectors/github.js +330 -0
- package/plugins/debate/lib/collectors/index.js +126 -0
- package/plugins/debate/lib/config/index.js +14 -0
- package/plugins/debate/lib/cross-platform/index.js +539 -0
- package/plugins/debate/lib/discovery/index.js +352 -0
- package/plugins/debate/lib/drift-detect/collectors.js +37 -0
- package/plugins/debate/lib/enhance/agent-analyzer.js +421 -0
- package/plugins/debate/lib/enhance/agent-patterns.js +571 -0
- package/plugins/debate/lib/enhance/auto-suppression.js +622 -0
- package/plugins/debate/lib/enhance/benchmark.js +417 -0
- package/plugins/debate/lib/enhance/cross-file-analyzer.js +930 -0
- package/plugins/debate/lib/enhance/cross-file-patterns.js +370 -0
- package/plugins/debate/lib/enhance/docs-analyzer.js +325 -0
- package/plugins/debate/lib/enhance/docs-patterns.js +671 -0
- package/plugins/debate/lib/enhance/fixer.js +721 -0
- package/plugins/debate/lib/enhance/hook-analyzer.js +135 -0
- package/plugins/debate/lib/enhance/hook-patterns.js +40 -0
- package/plugins/debate/lib/enhance/index.js +127 -0
- package/plugins/debate/lib/enhance/plugin-analyzer.js +402 -0
- package/plugins/debate/lib/enhance/plugin-patterns.js +326 -0
- package/plugins/debate/lib/enhance/projectmemory-analyzer.js +551 -0
- package/plugins/debate/lib/enhance/projectmemory-patterns.js +617 -0
- package/plugins/debate/lib/enhance/prompt-analyzer.js +457 -0
- package/plugins/debate/lib/enhance/prompt-patterns.js +1484 -0
- package/plugins/debate/lib/enhance/reporter.js +1348 -0
- package/plugins/debate/lib/enhance/security-patterns.js +284 -0
- package/plugins/debate/lib/enhance/skill-analyzer.js +182 -0
- package/plugins/debate/lib/enhance/skill-patterns.js +147 -0
- package/plugins/debate/lib/enhance/suppression.js +352 -0
- package/plugins/debate/lib/enhance/tool-patterns.js +373 -0
- package/plugins/debate/lib/index.js +270 -0
- package/plugins/debate/lib/patterns/cli-enhancers.js +611 -0
- package/plugins/debate/lib/patterns/pipeline.js +948 -0
- package/plugins/debate/lib/patterns/review-patterns.js +558 -0
- package/plugins/debate/lib/patterns/slop-analyzers.js +2305 -0
- package/plugins/debate/lib/patterns/slop-patterns.js +1187 -0
- package/plugins/debate/lib/perf/analyzer/index.js +22 -0
- package/plugins/debate/lib/perf/argument-parser.js +105 -0
- package/plugins/debate/lib/perf/baseline-comparator.js +50 -0
- package/plugins/debate/lib/perf/baseline-store.js +127 -0
- package/plugins/debate/lib/perf/benchmark-runner.js +404 -0
- package/plugins/debate/lib/perf/breaking-point-finder.js +52 -0
- package/plugins/debate/lib/perf/breaking-point-runner.js +60 -0
- package/plugins/debate/lib/perf/checkpoint.js +123 -0
- package/plugins/debate/lib/perf/code-paths.js +86 -0
- package/plugins/debate/lib/perf/consolidation.js +37 -0
- package/plugins/debate/lib/perf/constraint-runner.js +71 -0
- package/plugins/debate/lib/perf/experiment-runner.js +32 -0
- package/plugins/debate/lib/perf/index.js +41 -0
- package/plugins/debate/lib/perf/investigation-state.js +874 -0
- package/plugins/debate/lib/perf/optimization-runner.js +79 -0
- package/plugins/debate/lib/perf/profilers/go.js +22 -0
- package/plugins/debate/lib/perf/profilers/index.js +46 -0
- package/plugins/debate/lib/perf/profilers/java.js +23 -0
- package/plugins/debate/lib/perf/profilers/node.js +27 -0
- package/plugins/debate/lib/perf/profilers/python.js +23 -0
- package/plugins/debate/lib/perf/profilers/rust.js +23 -0
- package/plugins/debate/lib/perf/profiling-runner.js +75 -0
- package/plugins/debate/lib/perf/schemas.js +140 -0
- package/plugins/debate/lib/platform/detect-platform.js +413 -0
- package/plugins/debate/lib/platform/detection-configs.js +93 -0
- package/plugins/debate/lib/platform/state-dir.js +132 -0
- package/plugins/debate/lib/platform/verify-tools.js +182 -0
- package/plugins/debate/lib/repo-map/cache.js +152 -0
- package/plugins/debate/lib/repo-map/concurrency.js +29 -0
- package/plugins/debate/lib/repo-map/index.js +222 -0
- package/plugins/debate/lib/repo-map/installer.js +212 -0
- package/plugins/debate/lib/repo-map/queries/go.js +27 -0
- package/plugins/debate/lib/repo-map/queries/index.js +100 -0
- package/plugins/debate/lib/repo-map/queries/java.js +38 -0
- package/plugins/debate/lib/repo-map/queries/javascript.js +55 -0
- package/plugins/debate/lib/repo-map/queries/python.js +24 -0
- package/plugins/debate/lib/repo-map/queries/rust.js +73 -0
- package/plugins/debate/lib/repo-map/queries/typescript.js +38 -0
- package/plugins/debate/lib/repo-map/runner.js +1364 -0
- package/plugins/debate/lib/repo-map/updater.js +562 -0
- package/plugins/debate/lib/repo-map/usage-analyzer.js +407 -0
- package/plugins/debate/lib/schemas/plugin-manifest.schema.json +57 -0
- package/plugins/debate/lib/schemas/validator.js +247 -0
- package/plugins/debate/lib/sources/custom-handler.js +199 -0
- package/plugins/debate/lib/sources/policy-questions.js +246 -0
- package/plugins/debate/lib/sources/source-cache.js +165 -0
- package/plugins/debate/lib/state/workflow-state.js +576 -0
- package/plugins/debate/lib/types/agent-frontmatter.d.ts +134 -0
- package/plugins/debate/lib/types/command-frontmatter.d.ts +107 -0
- package/plugins/debate/lib/types/hook-frontmatter.d.ts +115 -0
- package/plugins/debate/lib/types/index.d.ts +84 -0
- package/plugins/debate/lib/types/plugin-manifest.d.ts +102 -0
- package/plugins/debate/lib/types/skill-frontmatter.d.ts +89 -0
- package/plugins/debate/lib/utils/atomic-write.js +94 -0
- package/plugins/debate/lib/utils/cache-manager.js +159 -0
- package/plugins/debate/lib/utils/command-parser.js +0 -0
- package/plugins/debate/lib/utils/context-optimizer.js +300 -0
- package/plugins/debate/lib/utils/deprecation.js +37 -0
- package/plugins/debate/lib/utils/shell-escape.js +88 -0
- package/plugins/debate/lib/utils/state-helpers.js +61 -0
- package/plugins/debate/skills/debate/SKILL.md +264 -0
- package/plugins/deslop/.claude-plugin/plugin.json +1 -1
- package/plugins/deslop/lib/adapter-transforms.js +24 -4
- package/plugins/deslop/skills/deslop/SKILL.md +1 -1
- package/plugins/drift-detect/.claude-plugin/plugin.json +1 -1
- package/plugins/drift-detect/lib/adapter-transforms.js +24 -4
- package/plugins/drift-detect/skills/drift-analysis/SKILL.md +1 -1
- package/plugins/enhance/.claude-plugin/plugin.json +1 -1
- package/plugins/enhance/lib/adapter-transforms.js +24 -4
- package/plugins/enhance/skills/enhance-agent-prompts/SKILL.md +1 -1
- package/plugins/enhance/skills/enhance-claude-memory/SKILL.md +1 -1
- package/plugins/enhance/skills/enhance-cross-file/SKILL.md +1 -1
- package/plugins/enhance/skills/enhance-docs/SKILL.md +1 -1
- package/plugins/enhance/skills/enhance-hooks/SKILL.md +1 -1
- package/plugins/enhance/skills/enhance-orchestrator/SKILL.md +1 -1
- package/plugins/enhance/skills/enhance-plugins/SKILL.md +1 -1
- package/plugins/enhance/skills/enhance-prompts/SKILL.md +1 -1
- package/plugins/enhance/skills/enhance-skills/SKILL.md +1 -1
- package/plugins/learn/.claude-plugin/plugin.json +1 -1
- package/plugins/learn/agents/learn-agent.md +1 -1
- package/plugins/learn/lib/adapter-transforms.js +24 -4
- package/plugins/learn/skills/learn/SKILL.md +1 -1
- package/plugins/next-task/.claude-plugin/plugin.json +1 -1
- package/plugins/next-task/agents/exploration-agent.md +1 -1
- package/plugins/next-task/lib/adapter-transforms.js +24 -4
- package/plugins/next-task/skills/discover-tasks/SKILL.md +1 -1
- package/plugins/next-task/skills/validate-delivery/SKILL.md +1 -1
- package/plugins/perf/.claude-plugin/plugin.json +1 -1
- package/plugins/perf/lib/adapter-transforms.js +24 -4
- package/plugins/perf/skills/perf-analyzer/SKILL.md +1 -1
- package/plugins/perf/skills/perf-baseline-manager/SKILL.md +1 -1
- package/plugins/perf/skills/perf-benchmarker/SKILL.md +1 -1
- package/plugins/perf/skills/perf-code-paths/SKILL.md +1 -1
- package/plugins/perf/skills/perf-investigation-logger/SKILL.md +1 -1
- package/plugins/perf/skills/perf-profiler/SKILL.md +1 -1
- package/plugins/perf/skills/perf-theory-gatherer/SKILL.md +1 -1
- package/plugins/perf/skills/perf-theory-tester/SKILL.md +1 -1
- package/plugins/repo-map/.claude-plugin/plugin.json +1 -1
- package/plugins/repo-map/lib/adapter-transforms.js +24 -4
- package/plugins/ship/.claude-plugin/plugin.json +1 -1
- package/plugins/ship/lib/adapter-transforms.js +24 -4
- package/plugins/sync-docs/.claude-plugin/plugin.json +1 -1
- package/plugins/sync-docs/lib/adapter-transforms.js +24 -4
- package/plugins/sync-docs/skills/sync-docs/SKILL.md +1 -1
- package/scripts/gen-adapters.js +6 -7
- package/scripts/generate-docs.js +4 -2
- package/scripts/plugins.txt +1 -0
- package/site/content.json +6 -6
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Documentation Collector
|
|
3
|
+
*
|
|
4
|
+
* Analyzes documentation files: README, PLAN, CHANGELOG, etc.
|
|
5
|
+
* Extracted from drift-detect/collectors.js for shared use.
|
|
6
|
+
*
|
|
7
|
+
* @module lib/collectors/documentation
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
'use strict';
|
|
11
|
+
|
|
12
|
+
const fs = require('fs');
|
|
13
|
+
const path = require('path');
|
|
14
|
+
|
|
15
|
+
const DEFAULT_OPTIONS = {
|
|
16
|
+
depth: 'thorough',
|
|
17
|
+
cwd: process.cwd()
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Validate file path to prevent path traversal
|
|
22
|
+
* @param {string} filePath - Path to validate
|
|
23
|
+
* @param {string} basePath - Base directory
|
|
24
|
+
* @returns {boolean} True if path is safe
|
|
25
|
+
*/
|
|
26
|
+
function isPathSafe(filePath, basePath) {
|
|
27
|
+
const resolved = path.resolve(basePath, filePath);
|
|
28
|
+
return resolved.startsWith(path.resolve(basePath));
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Safe file read with path validation
|
|
33
|
+
* @param {string} filePath - Path to read
|
|
34
|
+
* @param {string} basePath - Base directory for validation
|
|
35
|
+
* @returns {string|null} File contents or null
|
|
36
|
+
*/
|
|
37
|
+
function safeReadFile(filePath, basePath) {
|
|
38
|
+
const fullPath = path.resolve(basePath, filePath);
|
|
39
|
+
if (!isPathSafe(filePath, basePath)) {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
try {
|
|
43
|
+
return fs.readFileSync(fullPath, 'utf8');
|
|
44
|
+
} catch {
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Analyze a single markdown file
|
|
51
|
+
*/
|
|
52
|
+
function analyzeMarkdownFile(content, filePath) {
|
|
53
|
+
const sectionMatches = content.match(/^##\s+(.+)$/gm) || [];
|
|
54
|
+
const sections = sectionMatches.slice(0, 10).map(s => s.replace(/^##\s+/, ''));
|
|
55
|
+
const sectionLower = sections.map(s => s.toLowerCase()).join(' ');
|
|
56
|
+
|
|
57
|
+
return {
|
|
58
|
+
path: filePath,
|
|
59
|
+
sectionCount: sectionMatches.length,
|
|
60
|
+
sections,
|
|
61
|
+
hasInstallation: /install|setup|getting.started/i.test(sectionLower),
|
|
62
|
+
hasUsage: /usage|how.to|example/i.test(sectionLower),
|
|
63
|
+
hasApi: /api|reference|methods/i.test(sectionLower),
|
|
64
|
+
hasTesting: /test|spec|coverage/i.test(sectionLower),
|
|
65
|
+
codeBlocks: Math.floor((content.match(/```/g) || []).length / 2),
|
|
66
|
+
wordCount: content.split(/\s+/).length
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Extract checkboxes from content
|
|
72
|
+
*/
|
|
73
|
+
function extractCheckboxes(result, content) {
|
|
74
|
+
const checked = (content.match(/^[-*]\s+\[x\]/gim) || []).length;
|
|
75
|
+
const unchecked = (content.match(/^[-*]\s+\[\s\]/gim) || []).length;
|
|
76
|
+
|
|
77
|
+
result.checkboxes.checked += checked;
|
|
78
|
+
result.checkboxes.unchecked += unchecked;
|
|
79
|
+
result.checkboxes.total += checked + unchecked;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Extract documented features
|
|
84
|
+
*/
|
|
85
|
+
function extractFeatures(result, content) {
|
|
86
|
+
const featurePattern = /^[-*]\s+\*{0,2}(.+?)\*{0,2}(?:\s*[-–]\s*(.+))?$/gm;
|
|
87
|
+
let match;
|
|
88
|
+
|
|
89
|
+
while ((match = featurePattern.exec(content)) !== null && result.features.length < 20) {
|
|
90
|
+
const feature = match[1].trim();
|
|
91
|
+
if (feature.length > 5 && feature.length < 80) {
|
|
92
|
+
result.features.push(feature);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
result.features = [...new Set(result.features)].slice(0, 20);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Extract planned items from content
|
|
101
|
+
*/
|
|
102
|
+
function extractPlans(result, content) {
|
|
103
|
+
const planPatterns = [
|
|
104
|
+
/(?:TODO|FIXME|PLAN):\s*(.+)/gi,
|
|
105
|
+
/^##\s+(?:Roadmap|Future|Planned|Coming Soon)/gim
|
|
106
|
+
];
|
|
107
|
+
|
|
108
|
+
for (const pattern of planPatterns) {
|
|
109
|
+
let match;
|
|
110
|
+
while ((match = pattern.exec(content)) !== null && result.plans.length < 15) {
|
|
111
|
+
const plan = (match[1] || match[0]).slice(0, 100);
|
|
112
|
+
result.plans.push(plan);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Identify documentation gaps
|
|
119
|
+
*/
|
|
120
|
+
function identifyDocGaps(result) {
|
|
121
|
+
const readme = result.files['README.md'];
|
|
122
|
+
|
|
123
|
+
if (!readme) {
|
|
124
|
+
result.gaps.push({ type: 'missing', file: 'README.md', severity: 'high' });
|
|
125
|
+
} else {
|
|
126
|
+
if (!readme.hasInstallation) {
|
|
127
|
+
result.gaps.push({ type: 'missing-section', file: 'README.md', section: 'Installation', severity: 'medium' });
|
|
128
|
+
}
|
|
129
|
+
if (!readme.hasUsage) {
|
|
130
|
+
result.gaps.push({ type: 'missing-section', file: 'README.md', section: 'Usage', severity: 'medium' });
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (!result.files['CHANGELOG.md']) {
|
|
135
|
+
result.gaps.push({ type: 'missing', file: 'CHANGELOG.md', severity: 'low' });
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Analyze documentation files
|
|
141
|
+
* @param {Object} options - Collection options
|
|
142
|
+
* @returns {Object} Documentation analysis
|
|
143
|
+
*/
|
|
144
|
+
function analyzeDocumentation(options = {}) {
|
|
145
|
+
const opts = { ...DEFAULT_OPTIONS, ...options };
|
|
146
|
+
const basePath = opts.cwd;
|
|
147
|
+
|
|
148
|
+
const result = {
|
|
149
|
+
summary: { fileCount: 0, totalWords: 0 },
|
|
150
|
+
files: {},
|
|
151
|
+
features: [],
|
|
152
|
+
plans: [],
|
|
153
|
+
checkboxes: { total: 0, checked: 0, unchecked: 0 },
|
|
154
|
+
gaps: []
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
const docFiles = [
|
|
158
|
+
'README.md',
|
|
159
|
+
'PLAN.md',
|
|
160
|
+
'CLAUDE.md',
|
|
161
|
+
'AGENTS.md',
|
|
162
|
+
'CONTRIBUTING.md',
|
|
163
|
+
'CHANGELOG.md',
|
|
164
|
+
'docs/README.md',
|
|
165
|
+
'docs/PLAN.md'
|
|
166
|
+
];
|
|
167
|
+
|
|
168
|
+
for (const file of docFiles) {
|
|
169
|
+
const content = safeReadFile(file, basePath);
|
|
170
|
+
if (content) {
|
|
171
|
+
const analysis = analyzeMarkdownFile(content, file);
|
|
172
|
+
result.files[file] = analysis;
|
|
173
|
+
result.summary.totalWords += analysis.wordCount;
|
|
174
|
+
extractCheckboxes(result, content);
|
|
175
|
+
extractFeatures(result, content);
|
|
176
|
+
extractPlans(result, content);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// Find additional markdown files if depth is thorough
|
|
181
|
+
if (opts.depth === 'thorough') {
|
|
182
|
+
const docsDir = path.join(basePath, 'docs');
|
|
183
|
+
if (fs.existsSync(docsDir)) {
|
|
184
|
+
try {
|
|
185
|
+
const additionalFiles = fs.readdirSync(docsDir)
|
|
186
|
+
.filter(f => f.endsWith('.md') && !docFiles.includes(`docs/${f}`));
|
|
187
|
+
|
|
188
|
+
for (const file of additionalFiles.slice(0, 5)) {
|
|
189
|
+
const filePath = `docs/${file}`;
|
|
190
|
+
const content = safeReadFile(filePath, basePath);
|
|
191
|
+
if (content) {
|
|
192
|
+
const analysis = analyzeMarkdownFile(content, filePath);
|
|
193
|
+
result.files[filePath] = analysis;
|
|
194
|
+
result.summary.totalWords += analysis.wordCount;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
} catch {
|
|
198
|
+
// Ignore directory read errors
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
result.summary.fileCount = Object.keys(result.files).length;
|
|
204
|
+
identifyDocGaps(result);
|
|
205
|
+
|
|
206
|
+
return result;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
module.exports = {
|
|
210
|
+
DEFAULT_OPTIONS,
|
|
211
|
+
analyzeDocumentation,
|
|
212
|
+
analyzeMarkdownFile,
|
|
213
|
+
safeReadFile,
|
|
214
|
+
isPathSafe,
|
|
215
|
+
extractCheckboxes,
|
|
216
|
+
extractFeatures,
|
|
217
|
+
extractPlans,
|
|
218
|
+
identifyDocGaps
|
|
219
|
+
};
|
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GitHub Data Collector
|
|
3
|
+
*
|
|
4
|
+
* Collects GitHub state: issues, PRs, milestones.
|
|
5
|
+
* Extracted from drift-detect/collectors.js for shared use.
|
|
6
|
+
*
|
|
7
|
+
* @module lib/collectors/github
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
'use strict';
|
|
11
|
+
|
|
12
|
+
const { execFileSync } = require('child_process');
|
|
13
|
+
|
|
14
|
+
const DEFAULT_OPTIONS = {
|
|
15
|
+
issueLimit: 100,
|
|
16
|
+
prLimit: 50,
|
|
17
|
+
milestoneLimit: 100,
|
|
18
|
+
timeout: 10000,
|
|
19
|
+
cwd: process.cwd()
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Execute gh CLI command safely
|
|
24
|
+
* @param {string[]} args - Command arguments
|
|
25
|
+
* @param {Object} options - Execution options
|
|
26
|
+
* @returns {Object|null} Parsed JSON result or null
|
|
27
|
+
*/
|
|
28
|
+
function execGh(args, options = {}) {
|
|
29
|
+
const result = execGhWithResult(args, options);
|
|
30
|
+
return result.ok ? result.data : null;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function execGhWithResult(args, options = {}) {
|
|
34
|
+
try {
|
|
35
|
+
const output = execFileSync('gh', args, {
|
|
36
|
+
encoding: 'utf8',
|
|
37
|
+
stdio: 'pipe',
|
|
38
|
+
timeout: options.timeout || DEFAULT_OPTIONS.timeout,
|
|
39
|
+
cwd: options.cwd || DEFAULT_OPTIONS.cwd
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
try {
|
|
43
|
+
return { ok: true, data: JSON.parse(output) };
|
|
44
|
+
} catch (error) {
|
|
45
|
+
return {
|
|
46
|
+
ok: false,
|
|
47
|
+
error: {
|
|
48
|
+
type: 'parse',
|
|
49
|
+
message: `Failed to parse gh output as JSON: ${error.message}`,
|
|
50
|
+
raw: output.slice(0, 500)
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
} catch (error) {
|
|
55
|
+
return {
|
|
56
|
+
ok: false,
|
|
57
|
+
error: {
|
|
58
|
+
type: error.killed ? 'timeout' : 'process',
|
|
59
|
+
message: error.message,
|
|
60
|
+
exitCode: error.status ?? null,
|
|
61
|
+
stderr: error.stderr ? String(error.stderr).trim() : ''
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Check if gh CLI is available and authenticated
|
|
69
|
+
* @returns {boolean} True if gh is ready
|
|
70
|
+
*/
|
|
71
|
+
function isGhAvailable() {
|
|
72
|
+
try {
|
|
73
|
+
execFileSync('gh', ['auth', 'status'], {
|
|
74
|
+
encoding: 'utf8',
|
|
75
|
+
stdio: 'pipe',
|
|
76
|
+
timeout: 5000
|
|
77
|
+
});
|
|
78
|
+
return true;
|
|
79
|
+
} catch {
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Summarize an issue for analysis
|
|
86
|
+
* @param {Object} item - Issue object
|
|
87
|
+
* @returns {Object} Summarized item
|
|
88
|
+
*/
|
|
89
|
+
function summarizeIssue(item) {
|
|
90
|
+
return {
|
|
91
|
+
number: item.number,
|
|
92
|
+
title: item.title,
|
|
93
|
+
labels: (item.labels || []).map(l => l.name || l),
|
|
94
|
+
milestone: item.milestone?.title || item.milestone || null,
|
|
95
|
+
createdAt: item.createdAt,
|
|
96
|
+
updatedAt: item.updatedAt,
|
|
97
|
+
snippet: item.body ? item.body.slice(0, 200).replace(/\n/g, ' ').trim() + (item.body.length > 200 ? '...' : '') : ''
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Summarize a PR for analysis
|
|
103
|
+
* @param {Object} item - PR object
|
|
104
|
+
* @returns {Object} Summarized item
|
|
105
|
+
*/
|
|
106
|
+
function summarizePR(item) {
|
|
107
|
+
return {
|
|
108
|
+
number: item.number,
|
|
109
|
+
title: item.title,
|
|
110
|
+
labels: (item.labels || []).map(l => l.name || l),
|
|
111
|
+
isDraft: item.isDraft,
|
|
112
|
+
createdAt: item.createdAt,
|
|
113
|
+
updatedAt: item.updatedAt,
|
|
114
|
+
files: item.files || [],
|
|
115
|
+
snippet: item.body ? item.body.slice(0, 150).replace(/\n/g, ' ').trim() + (item.body.length > 150 ? '...' : '') : ''
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Categorize issues by labels
|
|
121
|
+
*/
|
|
122
|
+
function categorizeIssues(result, issues) {
|
|
123
|
+
const labelMap = {
|
|
124
|
+
bug: 'bugs',
|
|
125
|
+
'type: bug': 'bugs',
|
|
126
|
+
feature: 'features',
|
|
127
|
+
'type: feature': 'features',
|
|
128
|
+
enhancement: 'enhancements',
|
|
129
|
+
security: 'security',
|
|
130
|
+
'type: security': 'security'
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
const labelPatterns = Object.entries(labelMap).map(([pattern, category]) => ({
|
|
134
|
+
regex: new RegExp(`(^|[^a-z])${pattern.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}([^a-z]|$)`, 'i'),
|
|
135
|
+
category
|
|
136
|
+
}));
|
|
137
|
+
|
|
138
|
+
for (const issue of issues) {
|
|
139
|
+
const labels = (issue.labels || []).map(l => (l.name || l).toLowerCase());
|
|
140
|
+
let categorized = false;
|
|
141
|
+
const ref = { number: issue.number, title: issue.title };
|
|
142
|
+
|
|
143
|
+
for (const { regex, category } of labelPatterns) {
|
|
144
|
+
if (labels.some(l => regex.test(l))) {
|
|
145
|
+
result.categorized[category].push(ref);
|
|
146
|
+
categorized = true;
|
|
147
|
+
break;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (!categorized) {
|
|
152
|
+
result.categorized.other.push(ref);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Find stale items
|
|
159
|
+
*/
|
|
160
|
+
function findStaleItems(result, items, staleDays) {
|
|
161
|
+
const staleDate = new Date();
|
|
162
|
+
staleDate.setDate(staleDate.getDate() - staleDays);
|
|
163
|
+
|
|
164
|
+
for (const item of items) {
|
|
165
|
+
const updated = new Date(item.updatedAt);
|
|
166
|
+
if (updated < staleDate) {
|
|
167
|
+
result.stale.push({
|
|
168
|
+
number: item.number,
|
|
169
|
+
title: item.title,
|
|
170
|
+
lastUpdated: item.updatedAt,
|
|
171
|
+
daysStale: Math.floor((Date.now() - updated) / (1000 * 60 * 60 * 24))
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Extract common themes from issue titles
|
|
179
|
+
*/
|
|
180
|
+
function extractThemes(result, issues) {
|
|
181
|
+
const words = {};
|
|
182
|
+
const stopWords = new Set(['the', 'a', 'an', 'is', 'are', 'to', 'for', 'in', 'on', 'at', 'with', 'and', 'or', 'of']);
|
|
183
|
+
|
|
184
|
+
for (const issue of issues) {
|
|
185
|
+
const titleWords = (issue.title || '').toLowerCase().split(/\s+/);
|
|
186
|
+
for (const word of titleWords) {
|
|
187
|
+
if (word.length > 3 && !stopWords.has(word)) {
|
|
188
|
+
words[word] = (words[word] || 0) + 1;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
result.themes = Object.entries(words)
|
|
194
|
+
.filter(([, count]) => count > 1)
|
|
195
|
+
.sort((a, b) => b[1] - a[1])
|
|
196
|
+
.slice(0, 10)
|
|
197
|
+
.map(([word, count]) => ({ word, count }));
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Find overdue milestones
|
|
202
|
+
*/
|
|
203
|
+
function findOverdueMilestones(result) {
|
|
204
|
+
const now = new Date();
|
|
205
|
+
result.overdueMilestones = result.milestones.filter(m => {
|
|
206
|
+
if (!m.due_on || m.state === 'closed') return false;
|
|
207
|
+
return new Date(m.due_on) < now;
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Scan GitHub state: issues, PRs, milestones
|
|
213
|
+
* @param {Object} options - Collection options
|
|
214
|
+
* @returns {Object} GitHub state data
|
|
215
|
+
*/
|
|
216
|
+
function scanGitHubState(options = {}) {
|
|
217
|
+
const opts = { ...DEFAULT_OPTIONS, ...options };
|
|
218
|
+
|
|
219
|
+
const result = {
|
|
220
|
+
available: false,
|
|
221
|
+
partial: false,
|
|
222
|
+
errors: [],
|
|
223
|
+
summary: { issueCount: 0, prCount: 0, milestoneCount: 0 },
|
|
224
|
+
issues: [],
|
|
225
|
+
prs: [],
|
|
226
|
+
milestones: [],
|
|
227
|
+
overdueMilestones: [],
|
|
228
|
+
pagination: {
|
|
229
|
+
issues: { requestedLimit: opts.issueLimit, fetchedCount: 0, hasMore: false },
|
|
230
|
+
prs: { requestedLimit: opts.prLimit, fetchedCount: 0, hasMore: false },
|
|
231
|
+
milestones: { requestedLimit: opts.milestoneLimit, fetchedCount: 0, hasMore: false }
|
|
232
|
+
},
|
|
233
|
+
categorized: { bugs: [], features: [], security: [], enhancements: [], other: [] },
|
|
234
|
+
stale: [],
|
|
235
|
+
themes: []
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
if (!isGhAvailable()) {
|
|
239
|
+
result.error = 'gh CLI not available or not authenticated';
|
|
240
|
+
return result;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
result.available = true;
|
|
244
|
+
|
|
245
|
+
// Fetch open issues
|
|
246
|
+
const issuesResult = execGhWithResult([
|
|
247
|
+
'issue', 'list',
|
|
248
|
+
'--state', 'open',
|
|
249
|
+
'--json', 'number,title,labels,milestone,createdAt,updatedAt,body',
|
|
250
|
+
'--limit', String(opts.issueLimit)
|
|
251
|
+
], opts);
|
|
252
|
+
|
|
253
|
+
if (issuesResult.ok && Array.isArray(issuesResult.data)) {
|
|
254
|
+
const issues = issuesResult.data;
|
|
255
|
+
result.issues = issues.map(summarizeIssue);
|
|
256
|
+
result.summary.issueCount = issues.length;
|
|
257
|
+
result.pagination.issues.fetchedCount = issues.length;
|
|
258
|
+
result.pagination.issues.hasMore = opts.issueLimit > 0 && issues.length >= opts.issueLimit;
|
|
259
|
+
categorizeIssues(result, issues);
|
|
260
|
+
findStaleItems(result, issues, 90);
|
|
261
|
+
extractThemes(result, issues);
|
|
262
|
+
} else if (!issuesResult.ok) {
|
|
263
|
+
result.errors.push({ source: 'issues', ...issuesResult.error });
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// Fetch open PRs with files changed
|
|
267
|
+
const prsResult = execGhWithResult([
|
|
268
|
+
'pr', 'list',
|
|
269
|
+
'--state', 'open',
|
|
270
|
+
'--json', 'number,title,labels,isDraft,createdAt,updatedAt,body,files',
|
|
271
|
+
'--limit', String(opts.prLimit)
|
|
272
|
+
], opts);
|
|
273
|
+
|
|
274
|
+
if (prsResult.ok && Array.isArray(prsResult.data)) {
|
|
275
|
+
const prs = prsResult.data;
|
|
276
|
+
result.prs = prs.map(summarizePR);
|
|
277
|
+
result.summary.prCount = prs.length;
|
|
278
|
+
result.pagination.prs.fetchedCount = prs.length;
|
|
279
|
+
result.pagination.prs.hasMore = opts.prLimit > 0 && prs.length >= opts.prLimit;
|
|
280
|
+
} else if (!prsResult.ok) {
|
|
281
|
+
result.errors.push({ source: 'prs', ...prsResult.error });
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// Fetch milestones
|
|
285
|
+
const milestonesResult = execGhWithResult([
|
|
286
|
+
'api', 'repos/{owner}/{repo}/milestones',
|
|
287
|
+
'--paginate',
|
|
288
|
+
'--slurp'
|
|
289
|
+
], opts);
|
|
290
|
+
|
|
291
|
+
if (milestonesResult.ok && Array.isArray(milestonesResult.data)) {
|
|
292
|
+
const pages = milestonesResult.data;
|
|
293
|
+
const allMilestones = pages.flatMap(page => Array.isArray(page) ? page : []);
|
|
294
|
+
const mappedMilestones = allMilestones.map((milestone) => ({
|
|
295
|
+
title: milestone.title,
|
|
296
|
+
state: milestone.state,
|
|
297
|
+
due_on: milestone.due_on,
|
|
298
|
+
open_issues: milestone.open_issues,
|
|
299
|
+
closed_issues: milestone.closed_issues
|
|
300
|
+
}));
|
|
301
|
+
|
|
302
|
+
result.pagination.milestones.fetchedCount = mappedMilestones.length;
|
|
303
|
+
result.pagination.milestones.hasMore = opts.milestoneLimit > 0 && mappedMilestones.length > opts.milestoneLimit;
|
|
304
|
+
result.milestones = mappedMilestones.slice(0, opts.milestoneLimit);
|
|
305
|
+
result.summary.milestoneCount = result.milestones.length;
|
|
306
|
+
findOverdueMilestones(result);
|
|
307
|
+
} else if (!milestonesResult.ok) {
|
|
308
|
+
result.errors.push({ source: 'milestones', ...milestonesResult.error });
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
result.partial = result.errors.length > 0;
|
|
312
|
+
if (result.partial && !result.error) {
|
|
313
|
+
result.error = 'Partial GitHub data collected';
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
return result;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
module.exports = {
|
|
320
|
+
DEFAULT_OPTIONS,
|
|
321
|
+
scanGitHubState,
|
|
322
|
+
isGhAvailable,
|
|
323
|
+
execGh,
|
|
324
|
+
summarizeIssue,
|
|
325
|
+
summarizePR,
|
|
326
|
+
categorizeIssues,
|
|
327
|
+
findStaleItems,
|
|
328
|
+
extractThemes,
|
|
329
|
+
findOverdueMilestones
|
|
330
|
+
};
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared Data Collectors
|
|
3
|
+
*
|
|
4
|
+
* Composable data collection infrastructure for drift-detect, deslop, sync-docs.
|
|
5
|
+
* Follows the "JS collectors + single LLM call" pattern for token efficiency.
|
|
6
|
+
*
|
|
7
|
+
* @module lib/collectors
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
'use strict';
|
|
11
|
+
|
|
12
|
+
const github = require('./github');
|
|
13
|
+
const documentation = require('./documentation');
|
|
14
|
+
const codebase = require('./codebase');
|
|
15
|
+
const docsPatterns = require('./docs-patterns');
|
|
16
|
+
|
|
17
|
+
const DEFAULT_OPTIONS = {
|
|
18
|
+
collectors: ['github', 'docs', 'code'],
|
|
19
|
+
depth: 'thorough',
|
|
20
|
+
cwd: process.cwd()
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Collect data from specified collectors
|
|
25
|
+
*
|
|
26
|
+
* @param {Object} options - Collection options
|
|
27
|
+
* @param {string[]} options.collectors - Which collectors to run: 'github', 'docs', 'code', 'docs-patterns'
|
|
28
|
+
* @param {string} options.depth - 'quick' or 'thorough'
|
|
29
|
+
* @param {string} options.cwd - Working directory
|
|
30
|
+
* @param {string[]} options.changedFiles - For docs-patterns collector
|
|
31
|
+
* @returns {Object} Collected data
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* // Drift-detect uses all three
|
|
35
|
+
* const data = collect({ collectors: ['github', 'docs', 'code'] });
|
|
36
|
+
*
|
|
37
|
+
* // Deslop uses codebase only
|
|
38
|
+
* const data = collect({ collectors: ['code'] });
|
|
39
|
+
*
|
|
40
|
+
* // Sync-docs uses docs + docs-patterns
|
|
41
|
+
* const data = collect({ collectors: ['docs', 'docs-patterns'], changedFiles });
|
|
42
|
+
*/
|
|
43
|
+
function collect(options = {}) {
|
|
44
|
+
const opts = { ...DEFAULT_OPTIONS, ...options };
|
|
45
|
+
const collectors = Array.isArray(opts.collectors) ? opts.collectors : DEFAULT_OPTIONS.collectors;
|
|
46
|
+
|
|
47
|
+
const data = {
|
|
48
|
+
timestamp: new Date().toISOString(),
|
|
49
|
+
options: opts,
|
|
50
|
+
github: null,
|
|
51
|
+
docs: null,
|
|
52
|
+
code: null,
|
|
53
|
+
docsPatterns: null
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
// Collect from each enabled collector
|
|
57
|
+
if (collectors.includes('github')) {
|
|
58
|
+
data.github = github.scanGitHubState(opts);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (collectors.includes('docs')) {
|
|
62
|
+
data.docs = documentation.analyzeDocumentation(opts);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (collectors.includes('code')) {
|
|
66
|
+
data.code = codebase.scanCodebase(opts);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (collectors.includes('docs-patterns')) {
|
|
70
|
+
data.docsPatterns = docsPatterns.collect(opts);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return data;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Collect all data (backward compat with drift-detect)
|
|
78
|
+
*
|
|
79
|
+
* Supports both new 'collectors' option and legacy 'sources' option
|
|
80
|
+
*/
|
|
81
|
+
function collectAllData(options = {}) {
|
|
82
|
+
// Map legacy 'sources' option to 'collectors'
|
|
83
|
+
let collectors = ['github', 'docs', 'code'];
|
|
84
|
+
if (options.sources) {
|
|
85
|
+
collectors = options.sources;
|
|
86
|
+
} else if (options.collectors) {
|
|
87
|
+
collectors = options.collectors;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return collect({
|
|
91
|
+
...options,
|
|
92
|
+
collectors
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
module.exports = {
|
|
97
|
+
// Main entry point
|
|
98
|
+
collect,
|
|
99
|
+
collectAllData,
|
|
100
|
+
|
|
101
|
+
// Individual collectors
|
|
102
|
+
github,
|
|
103
|
+
documentation,
|
|
104
|
+
codebase,
|
|
105
|
+
docsPatterns,
|
|
106
|
+
|
|
107
|
+
// Re-export commonly used functions for convenience
|
|
108
|
+
scanGitHubState: github.scanGitHubState,
|
|
109
|
+
isGhAvailable: github.isGhAvailable,
|
|
110
|
+
analyzeDocumentation: documentation.analyzeDocumentation,
|
|
111
|
+
scanCodebase: codebase.scanCodebase,
|
|
112
|
+
findRelatedDocs: docsPatterns.findRelatedDocs,
|
|
113
|
+
analyzeDocIssues: docsPatterns.analyzeDocIssues,
|
|
114
|
+
checkChangelog: docsPatterns.checkChangelog,
|
|
115
|
+
|
|
116
|
+
// New: repo-map integration exports
|
|
117
|
+
ensureRepoMap: docsPatterns.ensureRepoMap,
|
|
118
|
+
ensureRepoMapSync: docsPatterns.ensureRepoMapSync,
|
|
119
|
+
getExportsFromRepoMap: docsPatterns.getExportsFromRepoMap,
|
|
120
|
+
findUndocumentedExports: docsPatterns.findUndocumentedExports,
|
|
121
|
+
isInternalExport: docsPatterns.isInternalExport,
|
|
122
|
+
isEntryPoint: docsPatterns.isEntryPoint,
|
|
123
|
+
|
|
124
|
+
// Constants
|
|
125
|
+
DEFAULT_OPTIONS
|
|
126
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration Module
|
|
3
|
+
*
|
|
4
|
+
* Placeholder for future configuration management.
|
|
5
|
+
* This module exists to satisfy lib/index.js imports.
|
|
6
|
+
*
|
|
7
|
+
* @module config
|
|
8
|
+
* @author Avi Fenesh
|
|
9
|
+
* @license MIT
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
module.exports = {
|
|
13
|
+
// Configuration will be added as needed
|
|
14
|
+
};
|