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,301 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Wogi Flow - Project Status Overview
|
|
5
|
+
*
|
|
6
|
+
* Shows task counts, features, bugs, components, and config summary.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* flow status Human-readable status
|
|
10
|
+
* flow status --json JSON output for programmatic access
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
const path = require('path');
|
|
14
|
+
|
|
15
|
+
const {
|
|
16
|
+
PATHS,
|
|
17
|
+
PROJECT_ROOT,
|
|
18
|
+
fileExists,
|
|
19
|
+
dirExists,
|
|
20
|
+
getTaskCounts,
|
|
21
|
+
getConfig,
|
|
22
|
+
getReadyData,
|
|
23
|
+
countRequestLogEntries,
|
|
24
|
+
countAppMapComponents,
|
|
25
|
+
getGitStatus,
|
|
26
|
+
listDirs,
|
|
27
|
+
listFiles,
|
|
28
|
+
parseFlags,
|
|
29
|
+
outputJson,
|
|
30
|
+
printHeader,
|
|
31
|
+
printSection,
|
|
32
|
+
color
|
|
33
|
+
} = require('./flow-utils');
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Collect all status data
|
|
37
|
+
*/
|
|
38
|
+
function collectStatus() {
|
|
39
|
+
const status = {
|
|
40
|
+
tasks: { ready: 0, inProgress: 0, blocked: 0, recentlyCompleted: 0 },
|
|
41
|
+
features: [],
|
|
42
|
+
bugs: [],
|
|
43
|
+
components: 0,
|
|
44
|
+
requestLog: 0,
|
|
45
|
+
git: { isRepo: false, branch: null, uncommitted: 0 },
|
|
46
|
+
cli: { type: 'claude-code', bridgeStatus: 'unknown' },
|
|
47
|
+
config: {},
|
|
48
|
+
recommendation: {}
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
// Task counts
|
|
52
|
+
if (fileExists(PATHS.ready)) {
|
|
53
|
+
status.tasks = getTaskCounts();
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Features
|
|
57
|
+
if (dirExists(PATHS.changes)) {
|
|
58
|
+
status.features = listDirs(PATHS.changes);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Bugs
|
|
62
|
+
if (dirExists(PATHS.bugs)) {
|
|
63
|
+
status.bugs = listFiles(PATHS.bugs, '.md').filter(f => !f.startsWith('.'));
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Components
|
|
67
|
+
if (fileExists(PATHS.appMap)) {
|
|
68
|
+
status.components = countAppMapComponents();
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Request log
|
|
72
|
+
if (fileExists(PATHS.requestLog)) {
|
|
73
|
+
status.requestLog = countRequestLogEntries();
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Git
|
|
77
|
+
status.git = getGitStatus();
|
|
78
|
+
|
|
79
|
+
// CLI
|
|
80
|
+
if (fileExists(PATHS.config)) {
|
|
81
|
+
try {
|
|
82
|
+
const config = getConfig();
|
|
83
|
+
status.cli.type = config.cli?.type || 'claude-code';
|
|
84
|
+
|
|
85
|
+
// Check bridge status
|
|
86
|
+
const bridgesDir = path.join(PROJECT_ROOT, '.workflow', 'bridges');
|
|
87
|
+
const modelsDir = path.join(PROJECT_ROOT, '.workflow', 'models');
|
|
88
|
+
|
|
89
|
+
if (dirExists(bridgesDir) && dirExists(modelsDir)) {
|
|
90
|
+
status.cli.bridgeStatus = 'configured';
|
|
91
|
+
} else if (config.cli?.type) {
|
|
92
|
+
status.cli.bridgeStatus = 'partial';
|
|
93
|
+
} else {
|
|
94
|
+
status.cli.bridgeStatus = 'legacy';
|
|
95
|
+
}
|
|
96
|
+
} catch {
|
|
97
|
+
status.cli.bridgeStatus = 'error';
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Config
|
|
102
|
+
if (fileExists(PATHS.config)) {
|
|
103
|
+
const config = getConfig();
|
|
104
|
+
status.config = {
|
|
105
|
+
mandatoryAfterTask: config.mandatorySteps?.afterTask || [],
|
|
106
|
+
strictMode: config.enforcement?.strictMode || false,
|
|
107
|
+
priorities: config.priorities || {}
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Recommendation
|
|
112
|
+
status.recommendation = getRecommendation();
|
|
113
|
+
|
|
114
|
+
return status;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function main() {
|
|
118
|
+
const { flags } = parseFlags(process.argv.slice(2));
|
|
119
|
+
|
|
120
|
+
const status = collectStatus();
|
|
121
|
+
|
|
122
|
+
// JSON output - exit early to avoid human-readable output
|
|
123
|
+
if (flags.json) {
|
|
124
|
+
outputJson({
|
|
125
|
+
success: true,
|
|
126
|
+
...status
|
|
127
|
+
});
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Human-readable output - use already collected status data
|
|
132
|
+
printHeader('PROJECT STATUS');
|
|
133
|
+
|
|
134
|
+
// Task counts (use status.tasks from collectStatus)
|
|
135
|
+
if (status.tasks.ready > 0 || status.tasks.inProgress > 0 || status.tasks.blocked > 0 || status.tasks.recentlyCompleted > 0) {
|
|
136
|
+
printSection('Tasks');
|
|
137
|
+
console.log(` Ready: ${status.tasks.ready}`);
|
|
138
|
+
console.log(` In Progress: ${status.tasks.inProgress}`);
|
|
139
|
+
console.log(` Blocked: ${status.tasks.blocked}`);
|
|
140
|
+
console.log(` Recently Done: ${status.tasks.recentlyCompleted}`);
|
|
141
|
+
console.log('');
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Features (use status.features from collectStatus)
|
|
145
|
+
if (status.features.length > 0 || dirExists(PATHS.changes)) {
|
|
146
|
+
printSection('Features');
|
|
147
|
+
console.log(` Active: ${status.features.length}`);
|
|
148
|
+
if (status.features.length > 0) {
|
|
149
|
+
for (const feature of status.features) {
|
|
150
|
+
console.log(` • ${feature}`);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
console.log('');
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Bugs (use status.bugs from collectStatus)
|
|
157
|
+
if (status.bugs.length > 0 || dirExists(PATHS.bugs)) {
|
|
158
|
+
printSection('Bugs');
|
|
159
|
+
console.log(` Open: ${status.bugs.length}`);
|
|
160
|
+
console.log('');
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Components (use status.components from collectStatus)
|
|
164
|
+
if (status.components > 0) {
|
|
165
|
+
printSection('Components');
|
|
166
|
+
console.log(` Mapped: ${status.components}`);
|
|
167
|
+
console.log('');
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Request log (use status.requestLog from collectStatus)
|
|
171
|
+
if (status.requestLog > 0) {
|
|
172
|
+
printSection('Request Log');
|
|
173
|
+
console.log(` Entries: ${status.requestLog}`);
|
|
174
|
+
console.log('');
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Git status (use status.git from collectStatus)
|
|
178
|
+
if (status.git.isRepo) {
|
|
179
|
+
printSection('Git');
|
|
180
|
+
console.log(` Branch: ${status.git.branch || 'unknown'}`);
|
|
181
|
+
console.log(` Uncommitted: ${status.git.uncommitted || 0} files`);
|
|
182
|
+
console.log('');
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// CLI status
|
|
186
|
+
printSection('CLI');
|
|
187
|
+
const cliNames = {
|
|
188
|
+
'claude-code': 'Claude Code',
|
|
189
|
+
'gemini-cli': 'Gemini CLI',
|
|
190
|
+
'opencode': 'OpenCode'
|
|
191
|
+
};
|
|
192
|
+
const bridgeColors = {
|
|
193
|
+
'configured': 'green',
|
|
194
|
+
'partial': 'yellow',
|
|
195
|
+
'legacy': 'yellow',
|
|
196
|
+
'error': 'red'
|
|
197
|
+
};
|
|
198
|
+
console.log(` Type: ${cliNames[status.cli.type] || status.cli.type}`);
|
|
199
|
+
console.log(` Bridge: ${color(bridgeColors[status.cli.bridgeStatus] || 'dim', status.cli.bridgeStatus)}`);
|
|
200
|
+
console.log('');
|
|
201
|
+
|
|
202
|
+
// Config summary (use status.config from collectStatus)
|
|
203
|
+
if (status.config.mandatoryAfterTask) {
|
|
204
|
+
printSection('Config');
|
|
205
|
+
const afterTask = status.config.mandatoryAfterTask;
|
|
206
|
+
|
|
207
|
+
if (afterTask.length > 0) {
|
|
208
|
+
console.log(` After task: ${afterTask.join(', ')}`);
|
|
209
|
+
} else {
|
|
210
|
+
console.log(' After task: (none)');
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// Action-oriented recommendation (use status.recommendation from collectStatus)
|
|
215
|
+
printSection('📌 Recommended Next Action');
|
|
216
|
+
console.log(` ${status.recommendation.action}`);
|
|
217
|
+
if (status.recommendation.command) {
|
|
218
|
+
console.log(color('dim', ` Run: ${status.recommendation.command}`));
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
console.log('');
|
|
222
|
+
console.log(color('cyan', '═'.repeat(50)));
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Get recommended next action based on current state
|
|
227
|
+
*/
|
|
228
|
+
function getRecommendation() {
|
|
229
|
+
const config = getConfig();
|
|
230
|
+
|
|
231
|
+
// Check for uncommitted changes first
|
|
232
|
+
const git = getGitStatus();
|
|
233
|
+
if (git.isRepo && git.uncommitted > 0) {
|
|
234
|
+
return {
|
|
235
|
+
action: `Commit ${git.uncommitted} uncommitted file(s)`,
|
|
236
|
+
command: 'git add -A && git commit -m "message"'
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// Check task state
|
|
241
|
+
if (!fileExists(PATHS.ready)) {
|
|
242
|
+
return {
|
|
243
|
+
action: 'Initialize workflow to start tracking tasks',
|
|
244
|
+
command: 'flow install'
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
const data = getReadyData();
|
|
249
|
+
|
|
250
|
+
// Check in-progress tasks first
|
|
251
|
+
const inProgress = data.inProgress || [];
|
|
252
|
+
if (inProgress.length > 0) {
|
|
253
|
+
const task = inProgress[0];
|
|
254
|
+
const taskId = typeof task === 'string' ? task : task.id;
|
|
255
|
+
const taskTitle = typeof task === 'object' ? (task.title || task.description || '') : '';
|
|
256
|
+
return {
|
|
257
|
+
action: `Continue working on ${taskId}${taskTitle ? `: ${taskTitle.slice(0, 40)}` : ''}`,
|
|
258
|
+
command: null
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// Check ready tasks
|
|
263
|
+
const ready = data.ready || [];
|
|
264
|
+
if (ready.length > 0) {
|
|
265
|
+
// Find highest priority task (P0=critical, P1=high, P2=medium, P3=low, P4=lowest)
|
|
266
|
+
const priorityOrder = { P0: 0, P1: 1, P2: 2, P3: 3, P4: 4 };
|
|
267
|
+
const sorted = [...ready].sort((a, b) => {
|
|
268
|
+
const aPriority = priorityOrder[a.priority] ?? 2;
|
|
269
|
+
const bPriority = priorityOrder[b.priority] ?? 2;
|
|
270
|
+
return aPriority - bPriority;
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
const task = sorted[0];
|
|
274
|
+
const taskId = typeof task === 'string' ? task : task.id;
|
|
275
|
+
const taskTitle = typeof task === 'object' ? (task.title || task.description || '') : '';
|
|
276
|
+
const priority = typeof task === 'object' && task.priority ? ` [${task.priority}]` : '';
|
|
277
|
+
return {
|
|
278
|
+
action: `Start ${taskId}${priority}${taskTitle ? `: ${taskTitle.slice(0, 35)}` : ''}`,
|
|
279
|
+
command: `flow start ${taskId}`
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// Check blocked tasks
|
|
284
|
+
const blocked = data.blocked || [];
|
|
285
|
+
if (blocked.length > 0) {
|
|
286
|
+
return {
|
|
287
|
+
action: `${blocked.length} task(s) are blocked - resolve dependencies`,
|
|
288
|
+
command: 'flow ready'
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// No tasks at all
|
|
293
|
+
return {
|
|
294
|
+
action: 'Create a new task to work on',
|
|
295
|
+
command: 'flow story "Your task title"'
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
if (require.main === module) {
|
|
300
|
+
main();
|
|
301
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Wogi Flow - Browser Test Step
|
|
5
|
+
*
|
|
6
|
+
* Workflow step wrapper for browser test suggestions.
|
|
7
|
+
* Suggests running browser tests for UI changes.
|
|
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 TESTS_DIR = path.join(PROJECT_ROOT, '.workflow', 'tests', 'flows');
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Run browser test step
|
|
19
|
+
*
|
|
20
|
+
* @param {object} options
|
|
21
|
+
* @param {string[]} options.files - Files modified in this task
|
|
22
|
+
* @param {string} options.taskId - Current task ID
|
|
23
|
+
* @param {object} options.stepConfig - Step configuration
|
|
24
|
+
* @param {string} options.mode - Step mode (block/warn/prompt/auto)
|
|
25
|
+
* @returns {object} - { passed: boolean, message: string, suggestion?: string }
|
|
26
|
+
*/
|
|
27
|
+
async function run(options = {}) {
|
|
28
|
+
const { files = [], mode, stepConfig = {} } = options;
|
|
29
|
+
|
|
30
|
+
// Check if we have any UI files
|
|
31
|
+
const uiExtensions = ['.tsx', '.jsx', '.vue', '.svelte'];
|
|
32
|
+
const uiFiles = files.filter(f => uiExtensions.some(ext => f.endsWith(ext)));
|
|
33
|
+
|
|
34
|
+
if (uiFiles.length === 0) {
|
|
35
|
+
return { passed: true, message: 'No UI files modified' };
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Check if browser tests exist
|
|
39
|
+
if (!fs.existsSync(TESTS_DIR)) {
|
|
40
|
+
return {
|
|
41
|
+
passed: true,
|
|
42
|
+
message: 'No browser test flows configured',
|
|
43
|
+
suggestion: 'Consider adding browser tests in .workflow/tests/flows/',
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Find available test flows
|
|
48
|
+
const testFlows = fs.readdirSync(TESTS_DIR)
|
|
49
|
+
.filter(f => f.endsWith('.json') || f.endsWith('.yaml') || f.endsWith('.yml'));
|
|
50
|
+
|
|
51
|
+
if (testFlows.length === 0) {
|
|
52
|
+
return {
|
|
53
|
+
passed: true,
|
|
54
|
+
message: 'No browser test flows found',
|
|
55
|
+
suggestion: 'Add test flows to .workflow/tests/flows/',
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// In prompt mode, suggest tests
|
|
60
|
+
if (mode === 'prompt') {
|
|
61
|
+
console.log(colors.yellow + '\n UI files modified:' + colors.reset);
|
|
62
|
+
uiFiles.forEach(f => console.log(` - ${f}`));
|
|
63
|
+
console.log(colors.yellow + '\n Available browser tests:' + colors.reset);
|
|
64
|
+
testFlows.forEach(f => console.log(` - ${f.replace(/\.(json|ya?ml)$/, '')}`));
|
|
65
|
+
console.log(colors.cyan + '\n Run with: /wogi-test-browser <flow-name>' + colors.reset);
|
|
66
|
+
|
|
67
|
+
return {
|
|
68
|
+
passed: true,
|
|
69
|
+
message: 'Browser tests suggested',
|
|
70
|
+
suggestion: `/wogi-test-browser ${testFlows[0].replace(/\.(json|ya?ml)$/, '')}`,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// In auto mode, we could run tests automatically
|
|
75
|
+
// For now, just mark as passed with suggestion
|
|
76
|
+
return {
|
|
77
|
+
passed: true,
|
|
78
|
+
message: `${uiFiles.length} UI file(s) modified, browser tests available`,
|
|
79
|
+
suggestion: 'Run browser tests to verify UI changes',
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
module.exports = { run };
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Wogi Flow - Update Changelog Step
|
|
5
|
+
*
|
|
6
|
+
* Prompts or auto-generates changelog entries.
|
|
7
|
+
* Follows Keep a Changelog format.
|
|
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 CHANGELOG_PATH = path.join(PROJECT_ROOT, 'CHANGELOG.md');
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Run update changelog 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.taskType - Task type (feature/bugfix/refactor)
|
|
24
|
+
* @param {string[]} options.files - Files modified
|
|
25
|
+
* @param {object} options.stepConfig - Step configuration
|
|
26
|
+
* @param {string} options.mode - Step mode (block/warn/prompt/auto)
|
|
27
|
+
* @returns {object} - { passed: boolean, message: string, entry?: string }
|
|
28
|
+
*/
|
|
29
|
+
async function run(options = {}) {
|
|
30
|
+
const { taskId, taskTitle, taskType, files = [], mode, stepConfig = {} } = options;
|
|
31
|
+
|
|
32
|
+
// Determine changelog category
|
|
33
|
+
const category = getChangelogCategory(taskType, taskTitle, files);
|
|
34
|
+
|
|
35
|
+
// Generate suggested entry
|
|
36
|
+
const entry = generateEntry(taskId, taskTitle, category, files);
|
|
37
|
+
|
|
38
|
+
// In prompt mode, show suggestion
|
|
39
|
+
if (mode === 'prompt') {
|
|
40
|
+
console.log(colors.yellow + '\n Suggested changelog entry:' + colors.reset);
|
|
41
|
+
console.log(colors.gray + ` ### ${category}` + colors.reset);
|
|
42
|
+
console.log(` - ${entry}`);
|
|
43
|
+
|
|
44
|
+
if (!fs.existsSync(CHANGELOG_PATH)) {
|
|
45
|
+
console.log(colors.yellow + '\n CHANGELOG.md does not exist - will create if approved' + colors.reset);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return {
|
|
49
|
+
passed: true,
|
|
50
|
+
message: 'Changelog entry suggested',
|
|
51
|
+
entry,
|
|
52
|
+
category,
|
|
53
|
+
suggestion: `Add to CHANGELOG.md under ${category}`,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// In auto mode, add the entry
|
|
58
|
+
if (mode === 'auto') {
|
|
59
|
+
const result = addToChangelog(entry, category);
|
|
60
|
+
if (result.success) {
|
|
61
|
+
return {
|
|
62
|
+
passed: true,
|
|
63
|
+
message: 'Changelog entry added',
|
|
64
|
+
entry,
|
|
65
|
+
category,
|
|
66
|
+
};
|
|
67
|
+
} else {
|
|
68
|
+
return {
|
|
69
|
+
passed: false,
|
|
70
|
+
message: result.error,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// In warn mode, just report
|
|
76
|
+
return {
|
|
77
|
+
passed: true,
|
|
78
|
+
message: `Changelog entry ready: ${entry}`,
|
|
79
|
+
entry,
|
|
80
|
+
category,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Determine changelog category from task type
|
|
86
|
+
*/
|
|
87
|
+
function getChangelogCategory(taskType, taskTitle, files) {
|
|
88
|
+
// Explicit type mapping
|
|
89
|
+
const typeMap = {
|
|
90
|
+
feature: 'Added',
|
|
91
|
+
feat: 'Added',
|
|
92
|
+
add: 'Added',
|
|
93
|
+
bugfix: 'Fixed',
|
|
94
|
+
fix: 'Fixed',
|
|
95
|
+
refactor: 'Changed',
|
|
96
|
+
change: 'Changed',
|
|
97
|
+
update: 'Changed',
|
|
98
|
+
remove: 'Removed',
|
|
99
|
+
delete: 'Removed',
|
|
100
|
+
deprecate: 'Deprecated',
|
|
101
|
+
security: 'Security',
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
if (taskType && typeMap[taskType.toLowerCase()]) {
|
|
105
|
+
return typeMap[taskType.toLowerCase()];
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Infer from title
|
|
109
|
+
const titleLower = (taskTitle || '').toLowerCase();
|
|
110
|
+
|
|
111
|
+
if (titleLower.includes('add') || titleLower.includes('implement') || titleLower.includes('create')) {
|
|
112
|
+
return 'Added';
|
|
113
|
+
}
|
|
114
|
+
if (titleLower.includes('fix') || titleLower.includes('bug') || titleLower.includes('resolve')) {
|
|
115
|
+
return 'Fixed';
|
|
116
|
+
}
|
|
117
|
+
if (titleLower.includes('remove') || titleLower.includes('delete')) {
|
|
118
|
+
return 'Removed';
|
|
119
|
+
}
|
|
120
|
+
if (titleLower.includes('refactor') || titleLower.includes('update') || titleLower.includes('change')) {
|
|
121
|
+
return 'Changed';
|
|
122
|
+
}
|
|
123
|
+
if (titleLower.includes('deprecate')) {
|
|
124
|
+
return 'Deprecated';
|
|
125
|
+
}
|
|
126
|
+
if (titleLower.includes('security') || titleLower.includes('vulnerability')) {
|
|
127
|
+
return 'Security';
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Default to Changed
|
|
131
|
+
return 'Changed';
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Generate a changelog entry
|
|
136
|
+
*/
|
|
137
|
+
function generateEntry(taskId, taskTitle, category, files) {
|
|
138
|
+
// Clean up title
|
|
139
|
+
let entry = taskTitle || 'Update';
|
|
140
|
+
|
|
141
|
+
// Remove task ID prefix if present
|
|
142
|
+
entry = entry.replace(/^(TASK-\d+:?\s*)/i, '');
|
|
143
|
+
|
|
144
|
+
// Capitalize first letter
|
|
145
|
+
entry = entry.charAt(0).toUpperCase() + entry.slice(1);
|
|
146
|
+
|
|
147
|
+
// Add task reference
|
|
148
|
+
if (taskId) {
|
|
149
|
+
entry += ` (${taskId})`;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return entry;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Add entry to CHANGELOG.md
|
|
157
|
+
*/
|
|
158
|
+
function addToChangelog(entry, category) {
|
|
159
|
+
try {
|
|
160
|
+
let content;
|
|
161
|
+
|
|
162
|
+
if (fs.existsSync(CHANGELOG_PATH)) {
|
|
163
|
+
content = fs.readFileSync(CHANGELOG_PATH, 'utf8');
|
|
164
|
+
} else {
|
|
165
|
+
// Create new changelog
|
|
166
|
+
content = `# Changelog
|
|
167
|
+
|
|
168
|
+
All notable changes to this project will be documented in this file.
|
|
169
|
+
|
|
170
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
171
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
172
|
+
|
|
173
|
+
## [Unreleased]
|
|
174
|
+
|
|
175
|
+
`;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Find or create [Unreleased] section
|
|
179
|
+
const unreleasedMatch = content.match(/## \[Unreleased\]\n/);
|
|
180
|
+
if (!unreleasedMatch) {
|
|
181
|
+
// Add unreleased section after header
|
|
182
|
+
const headerEnd = content.indexOf('\n\n') + 2;
|
|
183
|
+
content = content.slice(0, headerEnd) + '## [Unreleased]\n\n' + content.slice(headerEnd);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Find or create category under Unreleased
|
|
187
|
+
const unreleasedIndex = content.indexOf('## [Unreleased]');
|
|
188
|
+
const nextVersionMatch = content.slice(unreleasedIndex + 15).match(/\n## \[/);
|
|
189
|
+
const unreleasedEnd = nextVersionMatch
|
|
190
|
+
? unreleasedIndex + 15 + nextVersionMatch.index
|
|
191
|
+
: content.length;
|
|
192
|
+
|
|
193
|
+
const unreleasedSection = content.slice(unreleasedIndex, unreleasedEnd);
|
|
194
|
+
|
|
195
|
+
// Check if category exists
|
|
196
|
+
const categoryRegex = new RegExp(`### ${category}\\n`);
|
|
197
|
+
const categoryMatch = unreleasedSection.match(categoryRegex);
|
|
198
|
+
|
|
199
|
+
if (categoryMatch) {
|
|
200
|
+
// Add under existing category
|
|
201
|
+
const categoryIndex = unreleasedIndex + categoryMatch.index + categoryMatch[0].length;
|
|
202
|
+
content = content.slice(0, categoryIndex) + `- ${entry}\n` + content.slice(categoryIndex);
|
|
203
|
+
} else {
|
|
204
|
+
// Add new category section
|
|
205
|
+
const insertIndex = unreleasedIndex + 16; // After "## [Unreleased]\n"
|
|
206
|
+
content = content.slice(0, insertIndex) + `\n### ${category}\n- ${entry}\n` + content.slice(insertIndex);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
fs.writeFileSync(CHANGELOG_PATH, content);
|
|
210
|
+
return { success: true };
|
|
211
|
+
|
|
212
|
+
} catch (error) {
|
|
213
|
+
return { success: false, error: error.message };
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
module.exports = { run, getChangelogCategory, generateEntry, addToChangelog };
|