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,403 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Wogi Flow - CLI Utilities
|
|
5
|
+
*
|
|
6
|
+
* Standardized CLI output and exit codes for composability and CI integration.
|
|
7
|
+
*
|
|
8
|
+
* Exit Codes:
|
|
9
|
+
* 0 - Success
|
|
10
|
+
* 1 - General failure
|
|
11
|
+
* 2 - Configuration error
|
|
12
|
+
* 3 - Validation error
|
|
13
|
+
* 4 - Not found
|
|
14
|
+
* 5 - Safety violation
|
|
15
|
+
* 6 - Timeout
|
|
16
|
+
* 7 - Dependency error
|
|
17
|
+
*
|
|
18
|
+
* Usage:
|
|
19
|
+
* const cli = require('./flow-cli');
|
|
20
|
+
* cli.output({ tasks: [...] }, { json: true });
|
|
21
|
+
* cli.success('Task completed');
|
|
22
|
+
* cli.fail('Something went wrong', 1);
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
const fs = require('fs');
|
|
26
|
+
const path = require('path');
|
|
27
|
+
const { colors: c, parseFlags: utilsParseFlags } = require('./flow-utils');
|
|
28
|
+
|
|
29
|
+
// Exit codes
|
|
30
|
+
const EXIT_CODES = {
|
|
31
|
+
SUCCESS: 0,
|
|
32
|
+
FAILURE: 1,
|
|
33
|
+
CONFIG_ERROR: 2,
|
|
34
|
+
VALIDATION_ERROR: 3,
|
|
35
|
+
NOT_FOUND: 4,
|
|
36
|
+
SAFETY_VIOLATION: 5,
|
|
37
|
+
TIMEOUT: 6,
|
|
38
|
+
DEPENDENCY_ERROR: 7
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Global CLI options
|
|
43
|
+
*/
|
|
44
|
+
let globalOptions = {
|
|
45
|
+
json: false,
|
|
46
|
+
quiet: false,
|
|
47
|
+
verbose: false,
|
|
48
|
+
noColor: process.env.NO_COLOR === '1' || process.env.CI === 'true'
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Parse common CLI flags
|
|
53
|
+
* Uses the comprehensive implementation from flow-utils.js
|
|
54
|
+
*/
|
|
55
|
+
function parseFlags(args) {
|
|
56
|
+
// Use the flow-utils implementation which handles:
|
|
57
|
+
// - --key=value style
|
|
58
|
+
// - Valued flags (--priority, --from, etc.)
|
|
59
|
+
// - Named flags dictionary
|
|
60
|
+
return utilsParseFlags(args);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Configure global options
|
|
65
|
+
*/
|
|
66
|
+
function configure(options) {
|
|
67
|
+
globalOptions = { ...globalOptions, ...options };
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Get color code (respects NO_COLOR)
|
|
72
|
+
*/
|
|
73
|
+
function color(name) {
|
|
74
|
+
if (globalOptions.noColor || globalOptions.json) {
|
|
75
|
+
return '';
|
|
76
|
+
}
|
|
77
|
+
return c[name] || '';
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Standard output function
|
|
82
|
+
*/
|
|
83
|
+
function output(data, options = {}) {
|
|
84
|
+
const opts = { ...globalOptions, ...options };
|
|
85
|
+
|
|
86
|
+
if (opts.json) {
|
|
87
|
+
// JSON mode - machine readable
|
|
88
|
+
const jsonData = {
|
|
89
|
+
success: data.success !== false,
|
|
90
|
+
timestamp: new Date().toISOString(),
|
|
91
|
+
...data
|
|
92
|
+
};
|
|
93
|
+
console.log(JSON.stringify(jsonData, null, opts.pretty ? 2 : 0));
|
|
94
|
+
} else if (!opts.quiet) {
|
|
95
|
+
// Human readable mode
|
|
96
|
+
if (typeof data === 'string') {
|
|
97
|
+
console.log(data);
|
|
98
|
+
} else if (data.message) {
|
|
99
|
+
console.log(data.message);
|
|
100
|
+
} else {
|
|
101
|
+
console.log(JSON.stringify(data, null, 2));
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Success output
|
|
108
|
+
*/
|
|
109
|
+
function success(message, data = {}) {
|
|
110
|
+
if (globalOptions.json) {
|
|
111
|
+
output({ success: true, message, ...data });
|
|
112
|
+
} else if (!globalOptions.quiet) {
|
|
113
|
+
console.log(`${color('green')}✅ ${message}${color('reset')}`);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Warning output
|
|
119
|
+
*/
|
|
120
|
+
function warn(message, data = {}) {
|
|
121
|
+
if (globalOptions.json) {
|
|
122
|
+
output({ success: true, warning: message, ...data });
|
|
123
|
+
} else if (!globalOptions.quiet) {
|
|
124
|
+
console.log(`${color('yellow')}⚠️ ${message}${color('reset')}`);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Error output
|
|
130
|
+
*/
|
|
131
|
+
function error(message, data = {}) {
|
|
132
|
+
if (globalOptions.json) {
|
|
133
|
+
output({ success: false, error: message, ...data }, { json: true });
|
|
134
|
+
} else {
|
|
135
|
+
console.error(`${color('red')}❌ ${message}${color('reset')}`);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Info output
|
|
141
|
+
*/
|
|
142
|
+
function info(message) {
|
|
143
|
+
if (!globalOptions.json && !globalOptions.quiet) {
|
|
144
|
+
console.log(`${color('cyan')}ℹ ${color('reset')}${message}`);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Debug output (only in verbose mode)
|
|
150
|
+
*/
|
|
151
|
+
function debug(message) {
|
|
152
|
+
if (globalOptions.verbose && !globalOptions.json) {
|
|
153
|
+
console.log(`${color('dim')}[debug] ${message}${color('reset')}`);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Exit with code and optional message
|
|
159
|
+
*/
|
|
160
|
+
function exit(code, message = null, data = {}) {
|
|
161
|
+
if (message) {
|
|
162
|
+
if (code === EXIT_CODES.SUCCESS) {
|
|
163
|
+
success(message, data);
|
|
164
|
+
} else {
|
|
165
|
+
error(message, { code, ...data });
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
process.exit(code);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Fail with error message
|
|
173
|
+
*/
|
|
174
|
+
function fail(message, code = EXIT_CODES.FAILURE, data = {}) {
|
|
175
|
+
exit(code, message, data);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Create progress indicator
|
|
180
|
+
*/
|
|
181
|
+
function progress(current, total, label = '') {
|
|
182
|
+
if (globalOptions.json || globalOptions.quiet) return;
|
|
183
|
+
|
|
184
|
+
const width = 30;
|
|
185
|
+
const percent = Math.round((current / total) * 100);
|
|
186
|
+
const filled = Math.round((current / total) * width);
|
|
187
|
+
const empty = width - filled;
|
|
188
|
+
const bar = '█'.repeat(filled) + '░'.repeat(empty);
|
|
189
|
+
|
|
190
|
+
process.stdout.write(`\r${color('cyan')}${bar}${color('reset')} ${percent}% ${label}`);
|
|
191
|
+
|
|
192
|
+
if (current >= total) {
|
|
193
|
+
console.log(''); // New line at end
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Create a spinner for async operations
|
|
199
|
+
*/
|
|
200
|
+
function spinner(label) {
|
|
201
|
+
if (globalOptions.json || globalOptions.quiet) {
|
|
202
|
+
return { stop: () => {}, succeed: () => {}, fail: () => {} };
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
const frames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
|
|
206
|
+
let i = 0;
|
|
207
|
+
let running = true;
|
|
208
|
+
|
|
209
|
+
const interval = setInterval(() => {
|
|
210
|
+
if (running) {
|
|
211
|
+
process.stdout.write(`\r${color('cyan')}${frames[i % frames.length]}${color('reset')} ${label}`);
|
|
212
|
+
i++;
|
|
213
|
+
}
|
|
214
|
+
}, 80);
|
|
215
|
+
|
|
216
|
+
return {
|
|
217
|
+
stop: () => {
|
|
218
|
+
running = false;
|
|
219
|
+
clearInterval(interval);
|
|
220
|
+
process.stdout.write('\r' + ' '.repeat(label.length + 3) + '\r');
|
|
221
|
+
},
|
|
222
|
+
succeed: (msg) => {
|
|
223
|
+
running = false;
|
|
224
|
+
clearInterval(interval);
|
|
225
|
+
console.log(`\r${color('green')}✅${color('reset')} ${msg || label}`);
|
|
226
|
+
},
|
|
227
|
+
fail: (msg) => {
|
|
228
|
+
running = false;
|
|
229
|
+
clearInterval(interval);
|
|
230
|
+
console.log(`\r${color('red')}❌${color('reset')} ${msg || label}`);
|
|
231
|
+
}
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Format a table for display
|
|
237
|
+
*/
|
|
238
|
+
function table(data, columns = null) {
|
|
239
|
+
if (globalOptions.json) {
|
|
240
|
+
return JSON.stringify(data);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
if (data.length === 0) return '';
|
|
244
|
+
|
|
245
|
+
// Auto-detect columns from first row
|
|
246
|
+
const cols = columns || Object.keys(data[0]);
|
|
247
|
+
|
|
248
|
+
// Calculate column widths
|
|
249
|
+
const widths = {};
|
|
250
|
+
for (const col of cols) {
|
|
251
|
+
widths[col] = Math.max(
|
|
252
|
+
col.length,
|
|
253
|
+
...data.map(row => String(row[col] || '').length)
|
|
254
|
+
);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
let output = '';
|
|
258
|
+
|
|
259
|
+
// Header
|
|
260
|
+
output += cols.map(col => col.padEnd(widths[col])).join(' │ ') + '\n';
|
|
261
|
+
output += cols.map(col => '─'.repeat(widths[col])).join('─┼─') + '\n';
|
|
262
|
+
|
|
263
|
+
// Rows
|
|
264
|
+
for (const row of data) {
|
|
265
|
+
output += cols.map(col => String(row[col] || '').padEnd(widths[col])).join(' │ ') + '\n';
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
return output;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Format list items
|
|
273
|
+
*/
|
|
274
|
+
function list(items, options = {}) {
|
|
275
|
+
if (globalOptions.json) {
|
|
276
|
+
return JSON.stringify(items);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
const bullet = options.numbered ? (i) => `${i + 1}.` : () => '•';
|
|
280
|
+
|
|
281
|
+
return items.map((item, i) => ` ${bullet(i)} ${item}`).join('\n');
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Format key-value pairs
|
|
286
|
+
*/
|
|
287
|
+
function keyValue(obj, options = {}) {
|
|
288
|
+
if (globalOptions.json) {
|
|
289
|
+
return JSON.stringify(obj);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
const indent = options.indent || '';
|
|
293
|
+
const separator = options.separator || ': ';
|
|
294
|
+
|
|
295
|
+
return Object.entries(obj)
|
|
296
|
+
.map(([key, value]) => `${indent}${color('bold')}${key}${color('reset')}${separator}${value}`)
|
|
297
|
+
.join('\n');
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* Section header
|
|
302
|
+
*/
|
|
303
|
+
function section(title) {
|
|
304
|
+
if (globalOptions.json || globalOptions.quiet) return;
|
|
305
|
+
console.log(`\n${color('cyan')}${color('bold')}${title}${color('reset')}`);
|
|
306
|
+
console.log(color('dim') + '─'.repeat(title.length + 4) + color('reset'));
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Wrap async function with standard error handling
|
|
311
|
+
*/
|
|
312
|
+
function wrapAsync(fn) {
|
|
313
|
+
return async (...args) => {
|
|
314
|
+
try {
|
|
315
|
+
return await fn(...args);
|
|
316
|
+
} catch (err) {
|
|
317
|
+
if (err.isSafetyViolation) {
|
|
318
|
+
fail(err.message, EXIT_CODES.SAFETY_VIOLATION);
|
|
319
|
+
} else if (err.code === 'ENOENT') {
|
|
320
|
+
fail(`File not found: ${err.path}`, EXIT_CODES.NOT_FOUND);
|
|
321
|
+
} else if (err.name === 'SyntaxError') {
|
|
322
|
+
fail(`Configuration error: ${err.message}`, EXIT_CODES.CONFIG_ERROR);
|
|
323
|
+
} else {
|
|
324
|
+
fail(err.message, EXIT_CODES.FAILURE);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* Standard result wrapper for JSON output
|
|
332
|
+
*/
|
|
333
|
+
function result(success, data = {}, message = null) {
|
|
334
|
+
return {
|
|
335
|
+
success,
|
|
336
|
+
message,
|
|
337
|
+
timestamp: new Date().toISOString(),
|
|
338
|
+
...data
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// Module exports
|
|
343
|
+
module.exports = {
|
|
344
|
+
EXIT_CODES,
|
|
345
|
+
parseFlags,
|
|
346
|
+
configure,
|
|
347
|
+
color,
|
|
348
|
+
output,
|
|
349
|
+
success,
|
|
350
|
+
warn,
|
|
351
|
+
error,
|
|
352
|
+
info,
|
|
353
|
+
debug,
|
|
354
|
+
exit,
|
|
355
|
+
fail,
|
|
356
|
+
progress,
|
|
357
|
+
spinner,
|
|
358
|
+
table,
|
|
359
|
+
list,
|
|
360
|
+
keyValue,
|
|
361
|
+
section,
|
|
362
|
+
wrapAsync,
|
|
363
|
+
result,
|
|
364
|
+
|
|
365
|
+
// Color codes for direct access
|
|
366
|
+
c
|
|
367
|
+
};
|
|
368
|
+
|
|
369
|
+
// CLI Handler - show help when run directly
|
|
370
|
+
if (require.main === module) {
|
|
371
|
+
console.log(`
|
|
372
|
+
${c.cyan}Wogi Flow - CLI Utilities${c.reset}
|
|
373
|
+
|
|
374
|
+
This module provides standardized CLI output and exit codes.
|
|
375
|
+
|
|
376
|
+
${c.bold}Exit Codes:${c.reset}
|
|
377
|
+
0 SUCCESS Operation completed successfully
|
|
378
|
+
1 FAILURE General failure
|
|
379
|
+
2 CONFIG_ERROR Invalid configuration
|
|
380
|
+
3 VALIDATION_ERROR Validation failed
|
|
381
|
+
4 NOT_FOUND Resource not found
|
|
382
|
+
5 SAFETY_VIOLATION Safety guardrail triggered
|
|
383
|
+
6 TIMEOUT Operation timed out
|
|
384
|
+
7 DEPENDENCY_ERROR Missing dependency
|
|
385
|
+
|
|
386
|
+
${c.bold}Common Flags:${c.reset}
|
|
387
|
+
--json Output in JSON format
|
|
388
|
+
--quiet, -q Suppress non-essential output
|
|
389
|
+
--verbose, -v Show debug information
|
|
390
|
+
--help, -h Show help
|
|
391
|
+
--version Show version
|
|
392
|
+
|
|
393
|
+
${c.bold}Environment Variables:${c.reset}
|
|
394
|
+
NO_COLOR=1 Disable colored output
|
|
395
|
+
CI=true CI mode (implies NO_COLOR)
|
|
396
|
+
|
|
397
|
+
${c.bold}Usage in scripts:${c.reset}
|
|
398
|
+
const cli = require('./flow-cli');
|
|
399
|
+
cli.configure({ json: true });
|
|
400
|
+
cli.success('Done!');
|
|
401
|
+
cli.fail('Error', cli.EXIT_CODES.VALIDATION_ERROR);
|
|
402
|
+
`);
|
|
403
|
+
}
|