wogiflow 1.0.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/.workflow/agents/reviewer.md +81 -0
- package/.workflow/agents/security.md +94 -0
- package/.workflow/agents/story-writer.md +58 -0
- package/.workflow/bridges/base-bridge.js +395 -0
- package/.workflow/bridges/claude-bridge.js +434 -0
- package/.workflow/bridges/index.js +130 -0
- package/.workflow/lib/assumption-detector.js +481 -0
- package/.workflow/lib/config-substitution.js +371 -0
- package/.workflow/lib/failure-categories.js +478 -0
- package/.workflow/state/app-map.md.template +15 -0
- package/.workflow/state/architecture.md.template +24 -0
- package/.workflow/state/component-index.json.template +5 -0
- package/.workflow/state/decisions.md.template +15 -0
- package/.workflow/state/feedback-patterns.md.template +9 -0
- package/.workflow/state/knowledge-sync.json.template +6 -0
- package/.workflow/state/progress.md.template +14 -0
- package/.workflow/state/ready.json.template +7 -0
- package/.workflow/state/request-log.md.template +14 -0
- package/.workflow/state/session-state.json.template +11 -0
- package/.workflow/state/stack.md.template +33 -0
- package/.workflow/state/testing.md.template +36 -0
- package/.workflow/templates/claude-md.hbs +257 -0
- package/.workflow/templates/correction-report.md +67 -0
- package/.workflow/templates/gemini-md.hbs +52 -0
- package/README.md +1802 -0
- package/bin/flow +205 -0
- package/lib/index.js +33 -0
- package/lib/installer.js +467 -0
- package/lib/release-channel.js +269 -0
- package/lib/skill-registry.js +526 -0
- package/lib/upgrader.js +401 -0
- package/lib/utils.js +305 -0
- package/package.json +64 -0
- package/scripts/flow +985 -0
- package/scripts/flow-adaptive-learning.js +1259 -0
- package/scripts/flow-aggregate.js +488 -0
- package/scripts/flow-archive +133 -0
- package/scripts/flow-auto-context.js +1015 -0
- package/scripts/flow-auto-learn.js +615 -0
- package/scripts/flow-bridge.js +223 -0
- package/scripts/flow-browser-suggest.js +316 -0
- package/scripts/flow-bug.js +247 -0
- package/scripts/flow-cascade.js +711 -0
- package/scripts/flow-changelog +85 -0
- package/scripts/flow-checkpoint.js +483 -0
- package/scripts/flow-cli.js +403 -0
- package/scripts/flow-code-intelligence.js +760 -0
- package/scripts/flow-complexity.js +502 -0
- package/scripts/flow-config-set.js +152 -0
- package/scripts/flow-constants.js +157 -0
- package/scripts/flow-context +152 -0
- package/scripts/flow-context-init.js +482 -0
- package/scripts/flow-context-monitor.js +384 -0
- package/scripts/flow-context-scoring.js +886 -0
- package/scripts/flow-correct.js +458 -0
- package/scripts/flow-damage-control.js +985 -0
- package/scripts/flow-deps +101 -0
- package/scripts/flow-diff.js +700 -0
- package/scripts/flow-done +151 -0
- package/scripts/flow-done.js +489 -0
- package/scripts/flow-durable-session.js +1541 -0
- package/scripts/flow-entropy-monitor.js +345 -0
- package/scripts/flow-export-profile +349 -0
- package/scripts/flow-export-scanner.js +1046 -0
- package/scripts/flow-figma-confirm.js +400 -0
- package/scripts/flow-figma-extract.js +496 -0
- package/scripts/flow-figma-generate.js +683 -0
- package/scripts/flow-figma-index.js +909 -0
- package/scripts/flow-figma-match.js +617 -0
- package/scripts/flow-figma-mcp-server.js +518 -0
- package/scripts/flow-figma-pipeline.js +414 -0
- package/scripts/flow-file-ops.js +301 -0
- package/scripts/flow-gate-confidence.js +825 -0
- package/scripts/flow-guided-edit.js +659 -0
- package/scripts/flow-health +185 -0
- package/scripts/flow-health.js +413 -0
- package/scripts/flow-hooks.js +556 -0
- package/scripts/flow-http-client.js +249 -0
- package/scripts/flow-hybrid-detect.js +167 -0
- package/scripts/flow-hybrid-interactive.js +591 -0
- package/scripts/flow-hybrid-test.js +152 -0
- package/scripts/flow-import-profile +439 -0
- package/scripts/flow-init +253 -0
- package/scripts/flow-instruction-richness.js +827 -0
- package/scripts/flow-jira-integration.js +579 -0
- package/scripts/flow-knowledge-router.js +522 -0
- package/scripts/flow-knowledge-sync.js +589 -0
- package/scripts/flow-linear-integration.js +631 -0
- package/scripts/flow-links.js +774 -0
- package/scripts/flow-log-manager.js +559 -0
- package/scripts/flow-loop-enforcer.js +1246 -0
- package/scripts/flow-loop-retry-learning.js +630 -0
- package/scripts/flow-lsp.js +923 -0
- package/scripts/flow-map-index +348 -0
- package/scripts/flow-map-sync +201 -0
- package/scripts/flow-memory-blocks.js +668 -0
- package/scripts/flow-memory-compactor.js +350 -0
- package/scripts/flow-memory-db.js +1110 -0
- package/scripts/flow-memory-sync.js +484 -0
- package/scripts/flow-metrics.js +353 -0
- package/scripts/flow-migrate-ids.js +370 -0
- package/scripts/flow-model-adapter.js +802 -0
- package/scripts/flow-model-router.js +884 -0
- package/scripts/flow-models.js +1231 -0
- package/scripts/flow-morning.js +517 -0
- package/scripts/flow-multi-approach.js +660 -0
- package/scripts/flow-new-feature +86 -0
- package/scripts/flow-onboard +1042 -0
- package/scripts/flow-orchestrate-llm.js +459 -0
- package/scripts/flow-orchestrate.js +3592 -0
- package/scripts/flow-output.js +123 -0
- package/scripts/flow-parallel-detector.js +399 -0
- package/scripts/flow-parallel-dispatch.js +987 -0
- package/scripts/flow-parallel.js +428 -0
- package/scripts/flow-pattern-enforcer.js +600 -0
- package/scripts/flow-prd-manager.js +282 -0
- package/scripts/flow-progress.js +323 -0
- package/scripts/flow-project-analyzer.js +975 -0
- package/scripts/flow-prompt-composer.js +487 -0
- package/scripts/flow-providers.js +1381 -0
- package/scripts/flow-queue.js +308 -0
- package/scripts/flow-ready +82 -0
- package/scripts/flow-ready.js +189 -0
- package/scripts/flow-regression.js +396 -0
- package/scripts/flow-response-parser.js +450 -0
- package/scripts/flow-resume.js +284 -0
- package/scripts/flow-rules-sync.js +439 -0
- package/scripts/flow-run-trace.js +718 -0
- package/scripts/flow-safety.js +587 -0
- package/scripts/flow-search +104 -0
- package/scripts/flow-security.js +481 -0
- package/scripts/flow-session-end +106 -0
- package/scripts/flow-session-end.js +437 -0
- package/scripts/flow-session-state.js +671 -0
- package/scripts/flow-setup-hooks +216 -0
- package/scripts/flow-setup-hooks.js +377 -0
- package/scripts/flow-skill-create.js +329 -0
- package/scripts/flow-skill-creator.js +572 -0
- package/scripts/flow-skill-generator.js +1046 -0
- package/scripts/flow-skill-learn.js +880 -0
- package/scripts/flow-skill-matcher.js +578 -0
- package/scripts/flow-spec-generator.js +820 -0
- package/scripts/flow-stack-wizard.js +895 -0
- package/scripts/flow-standup +162 -0
- package/scripts/flow-start +74 -0
- package/scripts/flow-start.js +235 -0
- package/scripts/flow-status +110 -0
- package/scripts/flow-status.js +301 -0
- package/scripts/flow-step-browser.js +83 -0
- package/scripts/flow-step-changelog.js +217 -0
- package/scripts/flow-step-comments.js +306 -0
- package/scripts/flow-step-complexity.js +234 -0
- package/scripts/flow-step-coverage.js +218 -0
- package/scripts/flow-step-knowledge.js +193 -0
- package/scripts/flow-step-pr-tests.js +364 -0
- package/scripts/flow-step-regression.js +89 -0
- package/scripts/flow-step-review.js +516 -0
- package/scripts/flow-step-security.js +162 -0
- package/scripts/flow-step-silent-failures.js +290 -0
- package/scripts/flow-step-simplifier.js +346 -0
- package/scripts/flow-story +105 -0
- package/scripts/flow-story.js +500 -0
- package/scripts/flow-suspend.js +252 -0
- package/scripts/flow-sync-daemon.js +654 -0
- package/scripts/flow-task-analyzer.js +606 -0
- package/scripts/flow-team-dashboard.js +748 -0
- package/scripts/flow-team-sync.js +752 -0
- package/scripts/flow-team.js +977 -0
- package/scripts/flow-tech-options.js +528 -0
- package/scripts/flow-templates.js +812 -0
- package/scripts/flow-tiered-learning.js +728 -0
- package/scripts/flow-trace +204 -0
- package/scripts/flow-transcript-chunking.js +1106 -0
- package/scripts/flow-transcript-digest.js +7918 -0
- package/scripts/flow-transcript-language.js +465 -0
- package/scripts/flow-transcript-parsing.js +1085 -0
- package/scripts/flow-transcript-stories.js +2194 -0
- package/scripts/flow-update-map +224 -0
- package/scripts/flow-utils.js +2242 -0
- package/scripts/flow-verification.js +644 -0
- package/scripts/flow-verify.js +1177 -0
- package/scripts/flow-voice-input.js +638 -0
- package/scripts/flow-watch +168 -0
- package/scripts/flow-workflow-steps.js +521 -0
- package/scripts/flow-workflow.js +1029 -0
- package/scripts/flow-worktree.js +489 -0
- package/scripts/hooks/adapters/base-adapter.js +102 -0
- package/scripts/hooks/adapters/claude-code.js +359 -0
- package/scripts/hooks/adapters/index.js +79 -0
- package/scripts/hooks/core/component-check.js +341 -0
- package/scripts/hooks/core/index.js +35 -0
- package/scripts/hooks/core/loop-check.js +241 -0
- package/scripts/hooks/core/session-context.js +294 -0
- package/scripts/hooks/core/task-gate.js +177 -0
- package/scripts/hooks/core/validation.js +230 -0
- package/scripts/hooks/entry/claude-code/post-tool-use.js +65 -0
- package/scripts/hooks/entry/claude-code/pre-tool-use.js +89 -0
- package/scripts/hooks/entry/claude-code/session-end.js +87 -0
- package/scripts/hooks/entry/claude-code/session-start.js +46 -0
- package/scripts/hooks/entry/claude-code/stop.js +43 -0
- package/scripts/postinstall.js +139 -0
- package/templates/browser-test-flow.json +56 -0
- package/templates/bug-report.md +43 -0
- package/templates/component-detail.md +42 -0
- package/templates/component.stories.tsx +49 -0
- package/templates/context/constraints.md +83 -0
- package/templates/context/conventions.md +177 -0
- package/templates/context/stack.md +60 -0
- package/templates/correction-report.md +90 -0
- package/templates/feature-proposal.md +35 -0
- package/templates/hybrid/_base.md +254 -0
- package/templates/hybrid/_patterns.md +45 -0
- package/templates/hybrid/create-component.md +127 -0
- package/templates/hybrid/create-file.md +56 -0
- package/templates/hybrid/create-hook.md +145 -0
- package/templates/hybrid/create-service.md +70 -0
- package/templates/hybrid/fix-bug.md +33 -0
- package/templates/hybrid/modify-file.md +55 -0
- package/templates/story.md +68 -0
- package/templates/task.json +56 -0
- package/templates/trace.md +69 -0
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Wogi Flow - Coverage Check Step
|
|
5
|
+
*
|
|
6
|
+
* Checks test coverage meets threshold.
|
|
7
|
+
* Supports Jest, Vitest, NYC/Istanbul coverage formats.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const fs = require('fs');
|
|
11
|
+
const path = require('path');
|
|
12
|
+
const { execSync } = require('child_process');
|
|
13
|
+
const { getProjectRoot, colors, getConfig } = require('./flow-utils');
|
|
14
|
+
|
|
15
|
+
const PROJECT_ROOT = getProjectRoot();
|
|
16
|
+
|
|
17
|
+
// Common coverage output locations
|
|
18
|
+
const COVERAGE_PATHS = [
|
|
19
|
+
'coverage/coverage-summary.json', // Jest/Vitest JSON summary
|
|
20
|
+
'coverage/coverage-final.json', // Istanbul/NYC
|
|
21
|
+
'coverage/lcov-report/index.html', // LCOV HTML
|
|
22
|
+
'.nyc_output/coverage.json', // NYC output
|
|
23
|
+
];
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Run coverage check step
|
|
27
|
+
*
|
|
28
|
+
* @param {object} options
|
|
29
|
+
* @param {string[]} options.files - Files modified
|
|
30
|
+
* @param {object} options.stepConfig - Step configuration
|
|
31
|
+
* @param {string} options.mode - Step mode (block/warn/prompt/auto)
|
|
32
|
+
* @returns {object} - { passed: boolean, message: string, coverage?: object }
|
|
33
|
+
*/
|
|
34
|
+
async function run(options = {}) {
|
|
35
|
+
const { files = [], stepConfig = {}, mode } = options;
|
|
36
|
+
const minCoverage = stepConfig.minCoverage || 80;
|
|
37
|
+
const checkFiles = stepConfig.checkModifiedOnly ?? true;
|
|
38
|
+
|
|
39
|
+
// Try to find existing coverage data
|
|
40
|
+
let coverage = findExistingCoverage();
|
|
41
|
+
|
|
42
|
+
// If no coverage found, try to run tests with coverage
|
|
43
|
+
if (!coverage && stepConfig.runTests !== false) {
|
|
44
|
+
coverage = await runCoverageTests();
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (!coverage) {
|
|
48
|
+
return {
|
|
49
|
+
passed: true,
|
|
50
|
+
message: 'No coverage data available',
|
|
51
|
+
suggestion: 'Run tests with coverage: npm test -- --coverage',
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Check overall coverage
|
|
56
|
+
const overall = coverage.total || coverage;
|
|
57
|
+
const metrics = ['lines', 'statements', 'branches', 'functions'];
|
|
58
|
+
|
|
59
|
+
const results = {};
|
|
60
|
+
let allPassing = true;
|
|
61
|
+
|
|
62
|
+
for (const metric of metrics) {
|
|
63
|
+
if (overall[metric]) {
|
|
64
|
+
const pct = overall[metric].pct ?? overall[metric].percent ?? overall[metric];
|
|
65
|
+
if (typeof pct === 'number') {
|
|
66
|
+
results[metric] = pct;
|
|
67
|
+
if (pct < minCoverage) {
|
|
68
|
+
allPassing = false;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Check coverage for modified files specifically
|
|
75
|
+
let modifiedFileCoverage = null;
|
|
76
|
+
if (checkFiles && files.length > 0 && coverage.files) {
|
|
77
|
+
modifiedFileCoverage = checkModifiedFilesCoverage(files, coverage.files, minCoverage);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Report results
|
|
81
|
+
if (Object.keys(results).length > 0) {
|
|
82
|
+
console.log(colors.yellow + `\n Coverage (threshold: ${minCoverage}%):` + colors.reset);
|
|
83
|
+
for (const [metric, pct] of Object.entries(results)) {
|
|
84
|
+
const color = pct >= minCoverage ? colors.green : colors.red;
|
|
85
|
+
const icon = pct >= minCoverage ? '✓' : '✗';
|
|
86
|
+
console.log(` ${color}${icon}${colors.reset} ${metric}: ${pct.toFixed(1)}%`);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (modifiedFileCoverage && modifiedFileCoverage.uncovered.length > 0) {
|
|
91
|
+
console.log(colors.yellow + '\n Modified files with low coverage:' + colors.reset);
|
|
92
|
+
for (const file of modifiedFileCoverage.uncovered) {
|
|
93
|
+
console.log(colors.red + ` ✗ ${file.name}: ${file.coverage.toFixed(1)}%` + colors.reset);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (!allPassing) {
|
|
98
|
+
return {
|
|
99
|
+
passed: false,
|
|
100
|
+
message: `Coverage below ${minCoverage}% threshold`,
|
|
101
|
+
coverage: results,
|
|
102
|
+
modifiedFileCoverage,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return {
|
|
107
|
+
passed: true,
|
|
108
|
+
message: `Coverage meets ${minCoverage}% threshold`,
|
|
109
|
+
coverage: results,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Find existing coverage data
|
|
115
|
+
*/
|
|
116
|
+
function findExistingCoverage() {
|
|
117
|
+
for (const coveragePath of COVERAGE_PATHS) {
|
|
118
|
+
const fullPath = path.join(PROJECT_ROOT, coveragePath);
|
|
119
|
+
if (fs.existsSync(fullPath)) {
|
|
120
|
+
try {
|
|
121
|
+
if (coveragePath.endsWith('.json')) {
|
|
122
|
+
return JSON.parse(fs.readFileSync(fullPath, 'utf8'));
|
|
123
|
+
}
|
|
124
|
+
// For HTML reports, try to find accompanying JSON
|
|
125
|
+
const jsonPath = fullPath.replace('.html', '.json');
|
|
126
|
+
if (fs.existsSync(jsonPath)) {
|
|
127
|
+
return JSON.parse(fs.readFileSync(jsonPath, 'utf8'));
|
|
128
|
+
}
|
|
129
|
+
} catch (err) {
|
|
130
|
+
// Continue to next path
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Run tests with coverage
|
|
139
|
+
*/
|
|
140
|
+
async function runCoverageTests() {
|
|
141
|
+
// Check package.json for test script
|
|
142
|
+
const packagePath = path.join(PROJECT_ROOT, 'package.json');
|
|
143
|
+
if (!fs.existsSync(packagePath)) return null;
|
|
144
|
+
|
|
145
|
+
try {
|
|
146
|
+
const pkg = JSON.parse(fs.readFileSync(packagePath, 'utf8'));
|
|
147
|
+
const scripts = pkg.scripts || {};
|
|
148
|
+
|
|
149
|
+
// Try to find coverage command
|
|
150
|
+
let coverageCmd = null;
|
|
151
|
+
|
|
152
|
+
if (scripts['test:coverage']) {
|
|
153
|
+
coverageCmd = 'npm run test:coverage';
|
|
154
|
+
} else if (scripts.coverage) {
|
|
155
|
+
coverageCmd = 'npm run coverage';
|
|
156
|
+
} else if (scripts.test) {
|
|
157
|
+
// Try to add --coverage flag
|
|
158
|
+
if (scripts.test.includes('jest') || scripts.test.includes('vitest')) {
|
|
159
|
+
coverageCmd = 'npm test -- --coverage --json --outputFile=coverage/coverage-summary.json';
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if (!coverageCmd) return null;
|
|
164
|
+
|
|
165
|
+
// Run coverage
|
|
166
|
+
execSync(coverageCmd, {
|
|
167
|
+
cwd: PROJECT_ROOT,
|
|
168
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
169
|
+
timeout: 300000, // 5 minute timeout
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
// Try to read the output
|
|
173
|
+
return findExistingCoverage();
|
|
174
|
+
|
|
175
|
+
} catch (err) {
|
|
176
|
+
// Test run failed or timed out
|
|
177
|
+
return null;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Check coverage for specific modified files
|
|
183
|
+
*/
|
|
184
|
+
function checkModifiedFilesCoverage(files, coverageFiles, threshold) {
|
|
185
|
+
const covered = [];
|
|
186
|
+
const uncovered = [];
|
|
187
|
+
|
|
188
|
+
for (const file of files) {
|
|
189
|
+
// Skip test files
|
|
190
|
+
if (file.includes('.test.') || file.includes('.spec.')) continue;
|
|
191
|
+
|
|
192
|
+
// Skip non-code files
|
|
193
|
+
if (!file.match(/\.(js|ts|jsx|tsx)$/)) continue;
|
|
194
|
+
|
|
195
|
+
// Find in coverage data
|
|
196
|
+
const coverageKey = Object.keys(coverageFiles).find(k =>
|
|
197
|
+
k.endsWith(file) || k.includes(file)
|
|
198
|
+
);
|
|
199
|
+
|
|
200
|
+
if (coverageKey) {
|
|
201
|
+
const fileCov = coverageFiles[coverageKey];
|
|
202
|
+
const pct = fileCov.lines?.pct ?? fileCov.statements?.pct ?? 0;
|
|
203
|
+
|
|
204
|
+
if (pct >= threshold) {
|
|
205
|
+
covered.push({ name: file, coverage: pct });
|
|
206
|
+
} else {
|
|
207
|
+
uncovered.push({ name: file, coverage: pct });
|
|
208
|
+
}
|
|
209
|
+
} else {
|
|
210
|
+
// File not in coverage - might be new or not tested
|
|
211
|
+
uncovered.push({ name: file, coverage: 0, notFound: true });
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
return { covered, uncovered };
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
module.exports = { run, findExistingCoverage };
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Wogi Flow - Update Knowledge Base Step
|
|
5
|
+
*
|
|
6
|
+
* Prompts to document learnings in the knowledge base.
|
|
7
|
+
* Helps capture institutional knowledge automatically.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const fs = require('fs');
|
|
11
|
+
const path = require('path');
|
|
12
|
+
const { getProjectRoot, colors, getConfig } = require('./flow-utils');
|
|
13
|
+
|
|
14
|
+
const PROJECT_ROOT = getProjectRoot();
|
|
15
|
+
const KNOWLEDGE_DIR = path.join(PROJECT_ROOT, '.claude', 'docs', 'knowledge-base');
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Run update knowledge base step
|
|
19
|
+
*
|
|
20
|
+
* @param {object} options
|
|
21
|
+
* @param {string} options.taskId - Current task ID
|
|
22
|
+
* @param {string} options.taskTitle - Task title/description
|
|
23
|
+
* @param {string[]} options.files - Files modified
|
|
24
|
+
* @param {object} options.stepConfig - Step configuration
|
|
25
|
+
* @param {string} options.mode - Step mode (block/warn/prompt/auto)
|
|
26
|
+
* @param {object} options.learnings - Any learnings discovered during task
|
|
27
|
+
* @returns {object} - { passed: boolean, message: string, suggestion?: string }
|
|
28
|
+
*/
|
|
29
|
+
async function run(options = {}) {
|
|
30
|
+
const { taskId, taskTitle, files = [], mode, stepConfig = {}, learnings } = options;
|
|
31
|
+
|
|
32
|
+
// Ensure knowledge base directory exists
|
|
33
|
+
if (!fs.existsSync(KNOWLEDGE_DIR)) {
|
|
34
|
+
fs.mkdirSync(KNOWLEDGE_DIR, { recursive: true });
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Detect potential learnings based on task
|
|
38
|
+
const detectedLearnings = detectLearnings(files, taskTitle);
|
|
39
|
+
|
|
40
|
+
if (detectedLearnings.length === 0 && !learnings) {
|
|
41
|
+
return { passed: true, message: 'No learnings detected to document' };
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// In prompt mode, suggest documentation
|
|
45
|
+
if (mode === 'prompt') {
|
|
46
|
+
console.log(colors.yellow + '\n Potential learnings to document:' + colors.reset);
|
|
47
|
+
|
|
48
|
+
if (learnings) {
|
|
49
|
+
console.log(` - ${learnings}`);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
detectedLearnings.forEach(l => {
|
|
53
|
+
console.log(` - ${l.type}: ${l.description}`);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
console.log(colors.cyan + '\n Knowledge base location: .claude/docs/knowledge-base/' + colors.reset);
|
|
57
|
+
|
|
58
|
+
// Suggest where to document
|
|
59
|
+
const suggestion = suggestKnowledgeFile(detectedLearnings, taskTitle);
|
|
60
|
+
if (suggestion) {
|
|
61
|
+
console.log(colors.cyan + ` Suggested file: ${suggestion}` + colors.reset);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return {
|
|
65
|
+
passed: true,
|
|
66
|
+
message: 'Documentation prompt shown',
|
|
67
|
+
suggestion: `Document learnings in ${suggestion || 'knowledge-base'}`,
|
|
68
|
+
detectedLearnings,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// In auto mode, we could auto-create entries (future enhancement)
|
|
73
|
+
return {
|
|
74
|
+
passed: true,
|
|
75
|
+
message: `${detectedLearnings.length} potential learning(s) detected`,
|
|
76
|
+
suggestion: 'Consider documenting these patterns',
|
|
77
|
+
detectedLearnings,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Detect potential learnings based on files and task
|
|
83
|
+
*/
|
|
84
|
+
function detectLearnings(files, taskTitle) {
|
|
85
|
+
const learnings = [];
|
|
86
|
+
|
|
87
|
+
// Check for new patterns
|
|
88
|
+
const hasNewComponent = files.some(f =>
|
|
89
|
+
f.includes('/components/') && !f.includes('.test.') && !f.includes('.spec.')
|
|
90
|
+
);
|
|
91
|
+
if (hasNewComponent) {
|
|
92
|
+
learnings.push({
|
|
93
|
+
type: 'component',
|
|
94
|
+
description: 'New component created - document usage patterns',
|
|
95
|
+
category: 'components',
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Check for new hooks
|
|
100
|
+
const hasNewHook = files.some(f =>
|
|
101
|
+
f.includes('/hooks/') || (f.includes('use') && f.endsWith('.ts'))
|
|
102
|
+
);
|
|
103
|
+
if (hasNewHook) {
|
|
104
|
+
learnings.push({
|
|
105
|
+
type: 'hook',
|
|
106
|
+
description: 'Custom hook created - document API and usage',
|
|
107
|
+
category: 'hooks',
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Check for API endpoints
|
|
112
|
+
const hasApiChange = files.some(f =>
|
|
113
|
+
f.includes('/api/') || f.includes('.controller.') || f.includes('.routes.')
|
|
114
|
+
);
|
|
115
|
+
if (hasApiChange) {
|
|
116
|
+
learnings.push({
|
|
117
|
+
type: 'api',
|
|
118
|
+
description: 'API endpoint modified - document request/response format',
|
|
119
|
+
category: 'api',
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Check for configuration changes
|
|
124
|
+
const hasConfigChange = files.some(f =>
|
|
125
|
+
f.includes('config') || f.endsWith('.env.example') || f.includes('settings')
|
|
126
|
+
);
|
|
127
|
+
if (hasConfigChange) {
|
|
128
|
+
learnings.push({
|
|
129
|
+
type: 'configuration',
|
|
130
|
+
description: 'Configuration changed - document options',
|
|
131
|
+
category: 'configuration',
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Check for database/model changes
|
|
136
|
+
const hasModelChange = files.some(f =>
|
|
137
|
+
f.includes('/models/') || f.includes('/entities/') || f.includes('.schema.')
|
|
138
|
+
);
|
|
139
|
+
if (hasModelChange) {
|
|
140
|
+
learnings.push({
|
|
141
|
+
type: 'data-model',
|
|
142
|
+
description: 'Data model changed - document schema',
|
|
143
|
+
category: 'data-models',
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Check task title for patterns
|
|
148
|
+
const titleLower = (taskTitle || '').toLowerCase();
|
|
149
|
+
if (titleLower.includes('fix') || titleLower.includes('bug')) {
|
|
150
|
+
learnings.push({
|
|
151
|
+
type: 'bugfix',
|
|
152
|
+
description: 'Bug fixed - document root cause and solution',
|
|
153
|
+
category: 'troubleshooting',
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (titleLower.includes('performance') || titleLower.includes('optim')) {
|
|
158
|
+
learnings.push({
|
|
159
|
+
type: 'performance',
|
|
160
|
+
description: 'Performance improvement - document technique',
|
|
161
|
+
category: 'performance',
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return learnings;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Suggest knowledge base file based on learnings
|
|
170
|
+
*/
|
|
171
|
+
function suggestKnowledgeFile(learnings, taskTitle) {
|
|
172
|
+
if (learnings.length === 0) return null;
|
|
173
|
+
|
|
174
|
+
const primary = learnings[0];
|
|
175
|
+
const category = primary.category || 'general';
|
|
176
|
+
|
|
177
|
+
// Check if category file exists
|
|
178
|
+
const categoryFile = path.join(KNOWLEDGE_DIR, `${category}.md`);
|
|
179
|
+
if (fs.existsSync(categoryFile)) {
|
|
180
|
+
return `knowledge-base/${category}.md`;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// Check subdirectories
|
|
184
|
+
const categoryDir = path.join(KNOWLEDGE_DIR, category);
|
|
185
|
+
if (fs.existsSync(categoryDir)) {
|
|
186
|
+
return `knowledge-base/${category}/`;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Suggest new file
|
|
190
|
+
return `knowledge-base/${category}.md (new)`;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
module.exports = { run, detectLearnings };
|