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
package/bin/flow
ADDED
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Wogi Flow CLI Entry Point
|
|
5
|
+
*
|
|
6
|
+
* This is the main entry point for the `flow` command when installed globally via npm.
|
|
7
|
+
* It handles both global commands (init, upgrade, version) and project-local commands
|
|
8
|
+
* by delegating to the project's scripts/flow when in a project context.
|
|
9
|
+
*
|
|
10
|
+
* Usage:
|
|
11
|
+
* flow init # Initialize a new project
|
|
12
|
+
* flow upgrade # Upgrade an existing project
|
|
13
|
+
* flow --version # Show version
|
|
14
|
+
* flow <command> # Project commands (when in a project)
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
const path = require('path');
|
|
18
|
+
const fs = require('fs');
|
|
19
|
+
const { spawn } = require('child_process');
|
|
20
|
+
|
|
21
|
+
// Package info
|
|
22
|
+
const packageJson = require('../package.json');
|
|
23
|
+
const VERSION = packageJson.version;
|
|
24
|
+
|
|
25
|
+
// Global commands that don't require a project context
|
|
26
|
+
const GLOBAL_COMMANDS = ['init', 'upgrade', 'version', '--version', '-v', '--help', '-h', 'skill', 'channel'];
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Find the project root by looking for .workflow directory
|
|
30
|
+
* @returns {string|null} Project root path or null if not in a project
|
|
31
|
+
*/
|
|
32
|
+
function findProjectRoot() {
|
|
33
|
+
let dir = process.cwd();
|
|
34
|
+
const root = path.parse(dir).root;
|
|
35
|
+
|
|
36
|
+
while (dir !== root) {
|
|
37
|
+
if (fs.existsSync(path.join(dir, '.workflow'))) {
|
|
38
|
+
return dir;
|
|
39
|
+
}
|
|
40
|
+
dir = path.dirname(dir);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Execute a project-local flow command
|
|
48
|
+
* @param {string} projectRoot - Project root directory
|
|
49
|
+
* @param {string[]} args - Command arguments
|
|
50
|
+
*/
|
|
51
|
+
function executeProjectCommand(projectRoot, args) {
|
|
52
|
+
const projectFlow = path.join(projectRoot, 'scripts', 'flow');
|
|
53
|
+
|
|
54
|
+
if (!fs.existsSync(projectFlow)) {
|
|
55
|
+
console.error('Error: scripts/flow not found in project');
|
|
56
|
+
console.error('Run `flow upgrade` to update the project structure');
|
|
57
|
+
process.exit(1);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Spawn the project's flow script
|
|
61
|
+
// Note: shell: false (default) prevents command injection
|
|
62
|
+
const child = spawn(projectFlow, args, {
|
|
63
|
+
cwd: projectRoot,
|
|
64
|
+
stdio: 'inherit'
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
child.on('exit', (code) => {
|
|
68
|
+
process.exit(code || 0);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
child.on('error', (err) => {
|
|
72
|
+
console.error(`Failed to execute: ${err.message}`);
|
|
73
|
+
process.exit(1);
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Show version information
|
|
79
|
+
*/
|
|
80
|
+
function showVersion() {
|
|
81
|
+
console.log(`wogi-flow v${VERSION}`);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Show help information
|
|
86
|
+
*/
|
|
87
|
+
function showHelp() {
|
|
88
|
+
console.log(`
|
|
89
|
+
Wogi Flow v${VERSION}
|
|
90
|
+
AI-powered development workflow management
|
|
91
|
+
|
|
92
|
+
Usage: flow <command> [options]
|
|
93
|
+
|
|
94
|
+
Global Commands:
|
|
95
|
+
init Initialize Wogi Flow in a new project
|
|
96
|
+
upgrade Upgrade an existing project to latest version
|
|
97
|
+
--version, -v Show version number
|
|
98
|
+
--help, -h Show this help message
|
|
99
|
+
|
|
100
|
+
Project Commands (run in a project directory):
|
|
101
|
+
status Show project status
|
|
102
|
+
ready Show available tasks
|
|
103
|
+
start <task> Start working on a task
|
|
104
|
+
story "<title>" Create a new story
|
|
105
|
+
health Check workflow health
|
|
106
|
+
models Model management commands
|
|
107
|
+
... and many more
|
|
108
|
+
|
|
109
|
+
For project command help, run: flow --help (in a project directory)
|
|
110
|
+
|
|
111
|
+
Examples:
|
|
112
|
+
flow init # Set up Wogi Flow in current directory
|
|
113
|
+
flow init --cli claude # Initialize with Claude Code
|
|
114
|
+
flow upgrade # Upgrade project to latest version
|
|
115
|
+
flow status # Show project overview (in project)
|
|
116
|
+
|
|
117
|
+
Documentation: https://github.com/Wogi-Git/wogi-flow
|
|
118
|
+
`);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Main entry point
|
|
123
|
+
*/
|
|
124
|
+
function main() {
|
|
125
|
+
const args = process.argv.slice(2);
|
|
126
|
+
const command = args[0];
|
|
127
|
+
|
|
128
|
+
// Handle version flag
|
|
129
|
+
if (command === '--version' || command === '-v' || command === 'version') {
|
|
130
|
+
showVersion();
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Handle help flag
|
|
135
|
+
if (command === '--help' || command === '-h' || !command) {
|
|
136
|
+
const projectRoot = findProjectRoot();
|
|
137
|
+
if (projectRoot && command !== '--help' && command !== '-h') {
|
|
138
|
+
// In a project without args - show project help
|
|
139
|
+
executeProjectCommand(projectRoot, ['--help']);
|
|
140
|
+
} else {
|
|
141
|
+
showHelp();
|
|
142
|
+
}
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Handle global commands
|
|
147
|
+
if (command === 'init') {
|
|
148
|
+
// Load and run installer
|
|
149
|
+
const installer = require('../lib/installer');
|
|
150
|
+
installer.init(args.slice(1));
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (command === 'upgrade') {
|
|
155
|
+
// Load and run upgrader
|
|
156
|
+
const upgrader = require('../lib/upgrader');
|
|
157
|
+
upgrader.upgrade(args.slice(1));
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (command === 'skill') {
|
|
162
|
+
// Skill registry commands
|
|
163
|
+
const projectRoot = findProjectRoot();
|
|
164
|
+
if (!projectRoot && args[1] !== 'list') {
|
|
165
|
+
console.error('Error: Not in a Wogi Flow project');
|
|
166
|
+
console.error('Use `flow init` to initialize a new project');
|
|
167
|
+
process.exit(1);
|
|
168
|
+
}
|
|
169
|
+
if (projectRoot) {
|
|
170
|
+
// In project context - delegate to project scripts
|
|
171
|
+
executeProjectCommand(projectRoot, args);
|
|
172
|
+
} else {
|
|
173
|
+
// Outside project - only allow list
|
|
174
|
+
const skillRegistry = require('../lib/skill-registry');
|
|
175
|
+
skillRegistry.skill(args.slice(1));
|
|
176
|
+
}
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
if (command === 'channel') {
|
|
181
|
+
// Release channel management
|
|
182
|
+
const releaseChannel = require('../lib/release-channel');
|
|
183
|
+
releaseChannel.channel(args.slice(1));
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// For all other commands, try to find project context
|
|
188
|
+
const projectRoot = findProjectRoot();
|
|
189
|
+
|
|
190
|
+
if (!projectRoot) {
|
|
191
|
+
console.error('Error: Not in a Wogi Flow project');
|
|
192
|
+
console.error('');
|
|
193
|
+
console.error('To initialize a new project:');
|
|
194
|
+
console.error(' flow init');
|
|
195
|
+
console.error('');
|
|
196
|
+
console.error('To see all options:');
|
|
197
|
+
console.error(' flow --help');
|
|
198
|
+
process.exit(1);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Execute project-local command
|
|
202
|
+
executeProjectCommand(projectRoot, args);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
main();
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Wogi Flow Library Index
|
|
5
|
+
*
|
|
6
|
+
* Main entry point for the wogi-flow package.
|
|
7
|
+
* Exports all public modules for programmatic usage.
|
|
8
|
+
*
|
|
9
|
+
* @module wogi-flow
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const { init } = require('./installer');
|
|
13
|
+
const { upgrade } = require('./upgrader');
|
|
14
|
+
const { skill } = require('./skill-registry');
|
|
15
|
+
const { channel, CHANNELS, getLatestVersion } = require('./release-channel');
|
|
16
|
+
const utils = require('./utils');
|
|
17
|
+
|
|
18
|
+
module.exports = {
|
|
19
|
+
init,
|
|
20
|
+
upgrade,
|
|
21
|
+
skill,
|
|
22
|
+
channel,
|
|
23
|
+
|
|
24
|
+
// Release channel utilities
|
|
25
|
+
CHANNELS,
|
|
26
|
+
getLatestVersion,
|
|
27
|
+
|
|
28
|
+
// Shared utilities
|
|
29
|
+
utils,
|
|
30
|
+
|
|
31
|
+
// Version info
|
|
32
|
+
version: require('../package.json').version
|
|
33
|
+
};
|
package/lib/installer.js
ADDED
|
@@ -0,0 +1,467 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Wogi Flow Installer
|
|
5
|
+
*
|
|
6
|
+
* Handles project initialization with `flow init`.
|
|
7
|
+
* Creates the .workflow directory structure, configures CLI bridges,
|
|
8
|
+
* and sets up the project for use with the selected AI CLI.
|
|
9
|
+
*
|
|
10
|
+
* @module lib/installer
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
const fs = require('fs');
|
|
14
|
+
const path = require('path');
|
|
15
|
+
const readline = require('readline');
|
|
16
|
+
|
|
17
|
+
// Shared utilities
|
|
18
|
+
const { copyDir, safeReadJson } = require('./utils');
|
|
19
|
+
|
|
20
|
+
// Package root (where wogi-flow is installed)
|
|
21
|
+
const PACKAGE_ROOT = path.resolve(__dirname, '..');
|
|
22
|
+
|
|
23
|
+
// Supported CLIs
|
|
24
|
+
const SUPPORTED_CLIS = {
|
|
25
|
+
claude: {
|
|
26
|
+
name: 'Claude Code',
|
|
27
|
+
dir: '.claude',
|
|
28
|
+
configFile: 'CLAUDE.md',
|
|
29
|
+
description: 'Anthropic Claude Code CLI'
|
|
30
|
+
},
|
|
31
|
+
gemini: {
|
|
32
|
+
name: 'Gemini CLI',
|
|
33
|
+
dir: '.gemini',
|
|
34
|
+
configFile: 'GEMINI.md',
|
|
35
|
+
description: 'Google Gemini CLI'
|
|
36
|
+
},
|
|
37
|
+
opencode: {
|
|
38
|
+
name: 'OpenCode',
|
|
39
|
+
dir: '.opencode',
|
|
40
|
+
configFile: 'config.yaml',
|
|
41
|
+
description: 'OpenCode CLI'
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
// Default configuration
|
|
46
|
+
const DEFAULT_CONFIG = {
|
|
47
|
+
version: '1.9.0',
|
|
48
|
+
projectName: '',
|
|
49
|
+
cli: 'claude',
|
|
50
|
+
strictMode: true,
|
|
51
|
+
releaseChannel: 'stable'
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Parse command line arguments with bounds checking
|
|
56
|
+
* @param {string[]} args - Command line arguments
|
|
57
|
+
* @returns {Object} Parsed options
|
|
58
|
+
*/
|
|
59
|
+
function parseArgs(args) {
|
|
60
|
+
const options = {
|
|
61
|
+
cli: null,
|
|
62
|
+
force: false,
|
|
63
|
+
yes: false,
|
|
64
|
+
help: false
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
for (let i = 0; i < args.length; i++) {
|
|
68
|
+
const arg = args[i];
|
|
69
|
+
|
|
70
|
+
if (arg === '--cli' || arg === '-c') {
|
|
71
|
+
// Bounds check before accessing next argument
|
|
72
|
+
if (i + 1 >= args.length) {
|
|
73
|
+
console.error('Error: --cli requires a value');
|
|
74
|
+
options.help = true;
|
|
75
|
+
break;
|
|
76
|
+
}
|
|
77
|
+
options.cli = args[++i];
|
|
78
|
+
} else if (arg === '--force' || arg === '-f') {
|
|
79
|
+
options.force = true;
|
|
80
|
+
} else if (arg === '--yes' || arg === '-y') {
|
|
81
|
+
options.yes = true;
|
|
82
|
+
} else if (arg === '--help' || arg === '-h') {
|
|
83
|
+
options.help = true;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return options;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Show help message
|
|
92
|
+
*/
|
|
93
|
+
function showHelp() {
|
|
94
|
+
console.log(`
|
|
95
|
+
Usage: flow init [options]
|
|
96
|
+
|
|
97
|
+
Initialize Wogi Flow in the current directory.
|
|
98
|
+
|
|
99
|
+
Options:
|
|
100
|
+
--cli, -c <name> Select CLI (claude, gemini, opencode)
|
|
101
|
+
--force, -f Overwrite existing configuration
|
|
102
|
+
--yes, -y Accept all defaults without prompting
|
|
103
|
+
--help, -h Show this help message
|
|
104
|
+
|
|
105
|
+
Examples:
|
|
106
|
+
flow init # Interactive setup
|
|
107
|
+
flow init --cli claude # Initialize with Claude Code
|
|
108
|
+
flow init --cli claude -y # Quick setup with defaults
|
|
109
|
+
flow init --force # Reinitialize existing project
|
|
110
|
+
`);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Create readline interface for user input
|
|
115
|
+
* @returns {readline.Interface}
|
|
116
|
+
*/
|
|
117
|
+
function createReadline() {
|
|
118
|
+
return readline.createInterface({
|
|
119
|
+
input: process.stdin,
|
|
120
|
+
output: process.stdout
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Ask a question and get user input
|
|
126
|
+
* @param {readline.Interface} rl - Readline interface
|
|
127
|
+
* @param {string} question - Question to ask
|
|
128
|
+
* @param {string} defaultValue - Default value
|
|
129
|
+
* @returns {Promise<string>} User's answer
|
|
130
|
+
*/
|
|
131
|
+
function ask(rl, question, defaultValue = '') {
|
|
132
|
+
const prompt = defaultValue ? `${question} [${defaultValue}]: ` : `${question}: `;
|
|
133
|
+
return new Promise((resolve) => {
|
|
134
|
+
rl.question(prompt, (answer) => {
|
|
135
|
+
resolve(answer.trim() || defaultValue);
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Ask a yes/no question
|
|
142
|
+
* @param {readline.Interface} rl - Readline interface
|
|
143
|
+
* @param {string} question - Question to ask
|
|
144
|
+
* @param {boolean} defaultValue - Default value
|
|
145
|
+
* @returns {Promise<boolean>}
|
|
146
|
+
*/
|
|
147
|
+
async function askYesNo(rl, question, defaultValue = true) {
|
|
148
|
+
const hint = defaultValue ? '[Y/n]' : '[y/N]';
|
|
149
|
+
const answer = await ask(rl, `${question} ${hint}`, '');
|
|
150
|
+
if (!answer) return defaultValue;
|
|
151
|
+
return answer.toLowerCase().startsWith('y');
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Select from a list of options
|
|
156
|
+
* @param {readline.Interface} rl - Readline interface
|
|
157
|
+
* @param {string} question - Question to ask
|
|
158
|
+
* @param {Object} options - Options object {key: {name, description}}
|
|
159
|
+
* @param {string} defaultKey - Default selection
|
|
160
|
+
* @returns {Promise<string>} Selected key
|
|
161
|
+
*/
|
|
162
|
+
async function selectOption(rl, question, options, defaultKey) {
|
|
163
|
+
console.log(`\n${question}`);
|
|
164
|
+
const keys = Object.keys(options);
|
|
165
|
+
keys.forEach((key, index) => {
|
|
166
|
+
const opt = options[key];
|
|
167
|
+
const marker = key === defaultKey ? '>' : ' ';
|
|
168
|
+
console.log(` ${marker} ${index + 1}. ${opt.name} - ${opt.description}`);
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
const answer = await ask(rl, 'Enter number or name', defaultKey);
|
|
172
|
+
|
|
173
|
+
// Check if answer is a number
|
|
174
|
+
const num = parseInt(answer, 10);
|
|
175
|
+
if (!isNaN(num) && num >= 1 && num <= keys.length) {
|
|
176
|
+
return keys[num - 1];
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// Check if answer matches a key
|
|
180
|
+
if (options[answer.toLowerCase()]) {
|
|
181
|
+
return answer.toLowerCase();
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
return defaultKey;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// copyDir is imported from ./utils
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Create the .workflow directory structure
|
|
191
|
+
* @param {string} projectRoot - Project root directory
|
|
192
|
+
* @param {Object} config - Configuration options
|
|
193
|
+
*/
|
|
194
|
+
function createWorkflowStructure(projectRoot, config) {
|
|
195
|
+
const workflowDir = path.join(projectRoot, '.workflow');
|
|
196
|
+
|
|
197
|
+
// Create main directories
|
|
198
|
+
const dirs = [
|
|
199
|
+
'state',
|
|
200
|
+
'changes/general',
|
|
201
|
+
'models',
|
|
202
|
+
'templates',
|
|
203
|
+
'agents',
|
|
204
|
+
'bridges',
|
|
205
|
+
'roadmap',
|
|
206
|
+
'specs',
|
|
207
|
+
'verifications'
|
|
208
|
+
];
|
|
209
|
+
|
|
210
|
+
for (const dir of dirs) {
|
|
211
|
+
fs.mkdirSync(path.join(workflowDir, dir), { recursive: true });
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// Create config.json
|
|
215
|
+
const configPath = path.join(workflowDir, 'config.json');
|
|
216
|
+
const configContent = {
|
|
217
|
+
version: config.version,
|
|
218
|
+
projectName: config.projectName,
|
|
219
|
+
cli: config.cli,
|
|
220
|
+
enforcement: {
|
|
221
|
+
strictMode: config.strictMode,
|
|
222
|
+
requireTasks: true,
|
|
223
|
+
requireApproval: true
|
|
224
|
+
},
|
|
225
|
+
releaseChannel: config.releaseChannel,
|
|
226
|
+
autoUpdate: {
|
|
227
|
+
enabled: true,
|
|
228
|
+
notifyOnly: true
|
|
229
|
+
}
|
|
230
|
+
};
|
|
231
|
+
fs.writeFileSync(configPath, JSON.stringify(configContent, null, 2));
|
|
232
|
+
|
|
233
|
+
// Create ready.json
|
|
234
|
+
const readyPath = path.join(workflowDir, 'state', 'ready.json');
|
|
235
|
+
const readyContent = {
|
|
236
|
+
lastUpdated: new Date().toISOString(),
|
|
237
|
+
ready: [],
|
|
238
|
+
inProgress: [],
|
|
239
|
+
blocked: [],
|
|
240
|
+
recentlyCompleted: []
|
|
241
|
+
};
|
|
242
|
+
fs.writeFileSync(readyPath, JSON.stringify(readyContent, null, 2));
|
|
243
|
+
|
|
244
|
+
// Create empty state files
|
|
245
|
+
const stateFiles = [
|
|
246
|
+
{ name: 'request-log.md', content: '# Request Log\n\nAutomatic log of all requests that changed files.\n\n---\n' },
|
|
247
|
+
{ name: 'decisions.md', content: '# Project Decisions\n\nKey decisions and patterns for this project.\n\n---\n' },
|
|
248
|
+
{ name: 'app-map.md', content: '# Application Map\n\nComponent registry for this project.\n\n---\n' },
|
|
249
|
+
{ name: 'progress.md', content: '# Progress Notes\n\nSession handoff notes.\n\n---\n' }
|
|
250
|
+
];
|
|
251
|
+
|
|
252
|
+
for (const file of stateFiles) {
|
|
253
|
+
const filePath = path.join(workflowDir, 'state', file.name);
|
|
254
|
+
if (!fs.existsSync(filePath)) {
|
|
255
|
+
fs.writeFileSync(filePath, file.content);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// Create model registry
|
|
260
|
+
const registryPath = path.join(workflowDir, 'models', 'registry.json');
|
|
261
|
+
const registryContent = {
|
|
262
|
+
version: '1.0',
|
|
263
|
+
lastUpdated: new Date().toISOString(),
|
|
264
|
+
models: {}
|
|
265
|
+
};
|
|
266
|
+
fs.writeFileSync(registryPath, JSON.stringify(registryContent, null, 2));
|
|
267
|
+
|
|
268
|
+
// Copy templates from package
|
|
269
|
+
const packageTemplates = path.join(PACKAGE_ROOT, '.workflow', 'templates');
|
|
270
|
+
const projectTemplates = path.join(workflowDir, 'templates');
|
|
271
|
+
if (fs.existsSync(packageTemplates)) {
|
|
272
|
+
copyDir(packageTemplates, projectTemplates);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// Copy agents from package
|
|
276
|
+
const packageAgents = path.join(PACKAGE_ROOT, '.workflow', 'agents');
|
|
277
|
+
const projectAgents = path.join(workflowDir, 'agents');
|
|
278
|
+
if (fs.existsSync(packageAgents)) {
|
|
279
|
+
copyDir(packageAgents, projectAgents);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// Copy bridges from package
|
|
283
|
+
const packageBridges = path.join(PACKAGE_ROOT, '.workflow', 'bridges');
|
|
284
|
+
const projectBridges = path.join(workflowDir, 'bridges');
|
|
285
|
+
if (fs.existsSync(packageBridges)) {
|
|
286
|
+
copyDir(packageBridges, projectBridges);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
console.log(' Created .workflow/ directory structure');
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Create CLI-specific configuration
|
|
294
|
+
* @param {string} projectRoot - Project root directory
|
|
295
|
+
* @param {string} cliKey - CLI identifier
|
|
296
|
+
* @param {Object} config - Configuration
|
|
297
|
+
*/
|
|
298
|
+
function createCLIConfig(projectRoot, cliKey, config) {
|
|
299
|
+
const cli = SUPPORTED_CLIS[cliKey];
|
|
300
|
+
if (!cli) {
|
|
301
|
+
console.error(`Unknown CLI: ${cliKey}`);
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
const cliDir = path.join(projectRoot, cli.dir);
|
|
306
|
+
fs.mkdirSync(cliDir, { recursive: true });
|
|
307
|
+
|
|
308
|
+
// Create CLI-specific config file
|
|
309
|
+
if (cliKey === 'claude') {
|
|
310
|
+
const claudeMd = `# Project Instructions
|
|
311
|
+
|
|
312
|
+
You are an AI development assistant using the Wogi Flow methodology.
|
|
313
|
+
|
|
314
|
+
## Quick Start
|
|
315
|
+
|
|
316
|
+
\`\`\`bash
|
|
317
|
+
cat .workflow/config.json # Read config
|
|
318
|
+
cat .workflow/state/ready.json # Check tasks
|
|
319
|
+
\`\`\`
|
|
320
|
+
|
|
321
|
+
## Core Commands
|
|
322
|
+
|
|
323
|
+
- \`/wogi-ready\` - Show available tasks
|
|
324
|
+
- \`/wogi-start TASK-X\` - Start a task
|
|
325
|
+
- \`/wogi-status\` - Project overview
|
|
326
|
+
|
|
327
|
+
Generated by Wogi Flow v${config.version}
|
|
328
|
+
`;
|
|
329
|
+
fs.writeFileSync(path.join(cliDir, 'CLAUDE.md'), claudeMd);
|
|
330
|
+
|
|
331
|
+
// Create skills directory
|
|
332
|
+
fs.mkdirSync(path.join(cliDir, 'skills'), { recursive: true });
|
|
333
|
+
|
|
334
|
+
// Create docs directory
|
|
335
|
+
fs.mkdirSync(path.join(cliDir, 'docs'), { recursive: true });
|
|
336
|
+
|
|
337
|
+
// Create rules directory
|
|
338
|
+
fs.mkdirSync(path.join(cliDir, 'rules'), { recursive: true });
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
console.log(` Created ${cli.dir}/ for ${cli.name}`);
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* Copy scripts from package to project
|
|
346
|
+
* @param {string} projectRoot - Project root directory
|
|
347
|
+
*/
|
|
348
|
+
function copyScripts(projectRoot) {
|
|
349
|
+
const packageScripts = path.join(PACKAGE_ROOT, 'scripts');
|
|
350
|
+
const projectScripts = path.join(projectRoot, 'scripts');
|
|
351
|
+
|
|
352
|
+
if (fs.existsSync(packageScripts)) {
|
|
353
|
+
copyDir(packageScripts, projectScripts);
|
|
354
|
+
|
|
355
|
+
// Make flow script executable
|
|
356
|
+
const flowScript = path.join(projectScripts, 'flow');
|
|
357
|
+
if (fs.existsSync(flowScript)) {
|
|
358
|
+
fs.chmodSync(flowScript, '755');
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
console.log(' Copied scripts/ directory');
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
/**
|
|
366
|
+
* Main initialization function
|
|
367
|
+
* @param {string[]} args - Command line arguments
|
|
368
|
+
*/
|
|
369
|
+
async function init(args) {
|
|
370
|
+
const options = parseArgs(args);
|
|
371
|
+
|
|
372
|
+
if (options.help) {
|
|
373
|
+
showHelp();
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
const projectRoot = process.cwd();
|
|
378
|
+
const workflowDir = path.join(projectRoot, '.workflow');
|
|
379
|
+
|
|
380
|
+
// Check for existing installation
|
|
381
|
+
if (fs.existsSync(workflowDir) && !options.force) {
|
|
382
|
+
console.log('Wogi Flow is already initialized in this directory.');
|
|
383
|
+
console.log('Use --force to reinitialize.');
|
|
384
|
+
return;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
console.log('\n🚀 Wogi Flow Installer\n');
|
|
388
|
+
|
|
389
|
+
let config = { ...DEFAULT_CONFIG };
|
|
390
|
+
|
|
391
|
+
// Detect project name from package.json or directory name
|
|
392
|
+
const packageJsonPath = path.join(projectRoot, 'package.json');
|
|
393
|
+
const pkg = safeReadJson(packageJsonPath);
|
|
394
|
+
if (pkg && pkg.name) {
|
|
395
|
+
config.projectName = pkg.name;
|
|
396
|
+
} else {
|
|
397
|
+
config.projectName = path.basename(projectRoot);
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
// Interactive or quick mode
|
|
401
|
+
if (options.yes) {
|
|
402
|
+
// Use defaults and CLI option if provided
|
|
403
|
+
config.cli = options.cli || 'claude';
|
|
404
|
+
console.log(`Using quick mode with ${SUPPORTED_CLIS[config.cli].name}`);
|
|
405
|
+
} else {
|
|
406
|
+
// Interactive mode
|
|
407
|
+
const rl = createReadline();
|
|
408
|
+
|
|
409
|
+
try {
|
|
410
|
+
// Confirm project name
|
|
411
|
+
config.projectName = await ask(rl, 'Project name', config.projectName);
|
|
412
|
+
|
|
413
|
+
// Select CLI
|
|
414
|
+
config.cli = options.cli || await selectOption(
|
|
415
|
+
rl,
|
|
416
|
+
'Which AI CLI are you using?',
|
|
417
|
+
SUPPORTED_CLIS,
|
|
418
|
+
'claude'
|
|
419
|
+
);
|
|
420
|
+
|
|
421
|
+
// Enable strict mode?
|
|
422
|
+
config.strictMode = await askYesNo(
|
|
423
|
+
rl,
|
|
424
|
+
'Enable strict mode (require tasks for changes)?',
|
|
425
|
+
true
|
|
426
|
+
);
|
|
427
|
+
|
|
428
|
+
// Confirm
|
|
429
|
+
console.log('\nConfiguration:');
|
|
430
|
+
console.log(` Project: ${config.projectName}`);
|
|
431
|
+
console.log(` CLI: ${SUPPORTED_CLIS[config.cli].name}`);
|
|
432
|
+
console.log(` Strict Mode: ${config.strictMode ? 'Yes' : 'No'}`);
|
|
433
|
+
|
|
434
|
+
const proceed = await askYesNo(rl, '\nProceed with installation?', true);
|
|
435
|
+
if (!proceed) {
|
|
436
|
+
console.log('Installation cancelled.');
|
|
437
|
+
rl.close();
|
|
438
|
+
return;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
rl.close();
|
|
442
|
+
} catch (err) {
|
|
443
|
+
rl.close();
|
|
444
|
+
throw err;
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
console.log('\nInstalling Wogi Flow...\n');
|
|
449
|
+
|
|
450
|
+
// Create structure
|
|
451
|
+
createWorkflowStructure(projectRoot, config);
|
|
452
|
+
|
|
453
|
+
// Create CLI config
|
|
454
|
+
createCLIConfig(projectRoot, config.cli, config);
|
|
455
|
+
|
|
456
|
+
// Copy scripts
|
|
457
|
+
copyScripts(projectRoot);
|
|
458
|
+
|
|
459
|
+
console.log('\n✅ Wogi Flow initialized successfully!\n');
|
|
460
|
+
console.log('Next steps:');
|
|
461
|
+
console.log(' 1. Review .workflow/config.json');
|
|
462
|
+
console.log(' 2. Run `./scripts/flow status` to see project status');
|
|
463
|
+
console.log(' 3. Create your first task with `./scripts/flow story "Task title"`');
|
|
464
|
+
console.log('');
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
module.exports = { init };
|