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,434 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Claude Code Bridge
|
|
3
|
+
*
|
|
4
|
+
* Generates .claude/ folder structure and CLAUDE.md from .workflow/ configuration.
|
|
5
|
+
*
|
|
6
|
+
* Sync targets:
|
|
7
|
+
* - .workflow/skills/ → .claude/skills/
|
|
8
|
+
* - .workflow/rules/ → .claude/rules/
|
|
9
|
+
* - .workflow/config.json + templates → CLAUDE.md
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const fs = require('fs');
|
|
13
|
+
const path = require('path');
|
|
14
|
+
const BaseBridge = require('./base-bridge');
|
|
15
|
+
|
|
16
|
+
class ClaudeBridge extends BaseBridge {
|
|
17
|
+
constructor(options = {}) {
|
|
18
|
+
super('claude-code', options);
|
|
19
|
+
|
|
20
|
+
this.cliFolder = '.claude';
|
|
21
|
+
this.rulesFile = 'CLAUDE.md';
|
|
22
|
+
this.skillsPath = '.claude/skills';
|
|
23
|
+
this.rulesPath = '.claude/rules';
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
getCliFolder() {
|
|
27
|
+
return this.cliFolder;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
getRulesFileName() {
|
|
31
|
+
return this.rulesFile;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
getSkillsPath() {
|
|
35
|
+
return this.skillsPath;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
getRulesPath() {
|
|
39
|
+
return this.rulesPath;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Generate CLAUDE.md content from config
|
|
44
|
+
* @param {Object} config - The workflow config
|
|
45
|
+
* @returns {string} Generated CLAUDE.md content
|
|
46
|
+
*/
|
|
47
|
+
generateRulesContent(config) {
|
|
48
|
+
const projectName = config.projectName || 'Project';
|
|
49
|
+
|
|
50
|
+
// Check if custom template exists
|
|
51
|
+
const templatePath = path.join(this.projectDir, this.workflowDir, 'templates', 'claude-md.hbs');
|
|
52
|
+
if (fs.existsSync(templatePath)) {
|
|
53
|
+
return this.generateFromTemplate(templatePath, config);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Default template - comprehensive CLAUDE.md
|
|
57
|
+
return this.generateDefaultClaudeMd(config);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Generate CLAUDE.md from Handlebars template
|
|
62
|
+
*/
|
|
63
|
+
generateFromTemplate(templatePath, config) {
|
|
64
|
+
const template = fs.readFileSync(templatePath, 'utf-8');
|
|
65
|
+
|
|
66
|
+
// Simple template variable replacement (not full Handlebars)
|
|
67
|
+
let content = template;
|
|
68
|
+
|
|
69
|
+
// Replace {{variable}} patterns
|
|
70
|
+
content = content.replace(/\{\{(\w+)\}\}/g, (match, key) => {
|
|
71
|
+
return config[key] || match;
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
// Replace {{config.path.to.value}} patterns
|
|
75
|
+
content = content.replace(/\{\{config\.([^}]+)\}\}/g, (match, path) => {
|
|
76
|
+
const value = this.getNestedValue(config, path);
|
|
77
|
+
return value !== undefined ? String(value) : match;
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
return content;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Generate default CLAUDE.md when no template exists
|
|
85
|
+
*/
|
|
86
|
+
generateDefaultClaudeMd(config) {
|
|
87
|
+
const projectName = config.projectName || 'Project';
|
|
88
|
+
const skills = config.skills?.installed || [];
|
|
89
|
+
|
|
90
|
+
const sections = [];
|
|
91
|
+
|
|
92
|
+
// Header
|
|
93
|
+
sections.push(`# Project Instructions
|
|
94
|
+
|
|
95
|
+
You are an AI development assistant using the Wogi Flow methodology v1.9. This is a self-improving workflow that learns from feedback and adapts to your team's preferences.
|
|
96
|
+
|
|
97
|
+
---`);
|
|
98
|
+
|
|
99
|
+
// Task Gating Section (if strict mode enabled)
|
|
100
|
+
if (config.enforcement?.strictMode) {
|
|
101
|
+
sections.push(`
|
|
102
|
+
## Task Gating (MANDATORY)
|
|
103
|
+
|
|
104
|
+
**STOP. Before doing ANY implementation work, follow these steps:**
|
|
105
|
+
|
|
106
|
+
1. **Is this an implementation request?** (Adding, fixing, creating code)
|
|
107
|
+
- If NO → Proceed normally
|
|
108
|
+
- If YES → Continue to step 2
|
|
109
|
+
|
|
110
|
+
2. **Does a task already exist?**
|
|
111
|
+
- Check \`.workflow/state/ready.json\`
|
|
112
|
+
- If YES → Use \`/wogi-start TASK-XXX\`
|
|
113
|
+
- If NO → Continue to step 3
|
|
114
|
+
|
|
115
|
+
3. **Assess task size:**
|
|
116
|
+
- **Small** (< 3 files): Create task inline
|
|
117
|
+
- **Medium/Large** (3+ files): Create story first with \`/wogi-story\`
|
|
118
|
+
|
|
119
|
+
---`);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Quick Start
|
|
123
|
+
sections.push(`
|
|
124
|
+
## Quick Start
|
|
125
|
+
|
|
126
|
+
\`\`\`bash
|
|
127
|
+
cat .workflow/config.json # Read config
|
|
128
|
+
cat .workflow/state/ready.json # Check tasks
|
|
129
|
+
cat .workflow/state/decisions.md # Project rules
|
|
130
|
+
\`\`\`
|
|
131
|
+
|
|
132
|
+
---`);
|
|
133
|
+
|
|
134
|
+
// Essential Commands
|
|
135
|
+
sections.push(`
|
|
136
|
+
## Essential Commands
|
|
137
|
+
|
|
138
|
+
| Command | Purpose |
|
|
139
|
+
|---------|---------|
|
|
140
|
+
| \`/wogi-ready\` | Show available tasks |
|
|
141
|
+
| \`/wogi-start TASK-X\` | Start task (self-completing loop) |
|
|
142
|
+
| \`/wogi-story "title"\` | Create story with acceptance criteria |
|
|
143
|
+
| \`/wogi-status\` | Project overview |
|
|
144
|
+
| \`/wogi-health\` | Check workflow health |
|
|
145
|
+
|
|
146
|
+
---`);
|
|
147
|
+
|
|
148
|
+
// Auto-Validation
|
|
149
|
+
sections.push(`
|
|
150
|
+
## Auto-Validation (CRITICAL)
|
|
151
|
+
|
|
152
|
+
After editing ANY TypeScript/JavaScript file:
|
|
153
|
+
\`\`\`bash
|
|
154
|
+
npx tsc --noEmit 2>&1 | head -20
|
|
155
|
+
npx eslint [file] --fix
|
|
156
|
+
\`\`\`
|
|
157
|
+
|
|
158
|
+
**Do NOT edit another file until current file passes validation.**
|
|
159
|
+
|
|
160
|
+
---`);
|
|
161
|
+
|
|
162
|
+
// Skills Section
|
|
163
|
+
if (skills.length > 0) {
|
|
164
|
+
sections.push(`
|
|
165
|
+
## Installed Skills
|
|
166
|
+
|
|
167
|
+
${skills.map(s => `- ${s}`).join('\n')}
|
|
168
|
+
|
|
169
|
+
Check \`.claude/skills/[name]/skill.md\` for skill-specific guidance.
|
|
170
|
+
|
|
171
|
+
---`);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// File Locations
|
|
175
|
+
sections.push(`
|
|
176
|
+
## File Locations
|
|
177
|
+
|
|
178
|
+
| What | Where |
|
|
179
|
+
|------|-------|
|
|
180
|
+
| Config | \`.workflow/config.json\` |
|
|
181
|
+
| Tasks | \`.workflow/state/ready.json\` |
|
|
182
|
+
| Logs | \`.workflow/state/request-log.md\` |
|
|
183
|
+
| Components | \`.workflow/state/app-map.md\` |
|
|
184
|
+
| Rules | \`.workflow/state/decisions.md\` |
|
|
185
|
+
| Progress | \`.workflow/state/progress.md\` |
|
|
186
|
+
|
|
187
|
+
---`);
|
|
188
|
+
|
|
189
|
+
// Component Reuse
|
|
190
|
+
sections.push(`
|
|
191
|
+
## Component Reuse
|
|
192
|
+
|
|
193
|
+
**Before creating ANY component:**
|
|
194
|
+
1. Check \`app-map.md\`
|
|
195
|
+
2. Search codebase for existing
|
|
196
|
+
3. Priority: Use existing → Add variant → Extend → Create new (last resort)
|
|
197
|
+
|
|
198
|
+
---`);
|
|
199
|
+
|
|
200
|
+
// Commit Behavior
|
|
201
|
+
sections.push(`
|
|
202
|
+
## Commit Behavior
|
|
203
|
+
|
|
204
|
+
Check \`config.json → commits\` before committing:
|
|
205
|
+
- Features require user approval (default)
|
|
206
|
+
- Small fixes (≤${config.commits?.smallFixThreshold || 3} files) can auto-commit
|
|
207
|
+
- Always show git diff before committing features/refactors
|
|
208
|
+
|
|
209
|
+
---`);
|
|
210
|
+
|
|
211
|
+
// Context Management
|
|
212
|
+
sections.push(`
|
|
213
|
+
## Context Management
|
|
214
|
+
|
|
215
|
+
Use \`/wogi-compact\` when:
|
|
216
|
+
- After completing 2-3 tasks
|
|
217
|
+
- After 15-20 messages
|
|
218
|
+
- Before starting large tasks
|
|
219
|
+
|
|
220
|
+
---`);
|
|
221
|
+
|
|
222
|
+
// Footer
|
|
223
|
+
sections.push(`
|
|
224
|
+
## Generated by CLI Bridge
|
|
225
|
+
|
|
226
|
+
This file was generated by the Wogi Flow CLI bridge.
|
|
227
|
+
Edit \`.workflow/templates/claude-md.hbs\` to customize.
|
|
228
|
+
Run \`flow bridge sync\` to regenerate.
|
|
229
|
+
|
|
230
|
+
Last synced: ${new Date().toISOString()}
|
|
231
|
+
`);
|
|
232
|
+
|
|
233
|
+
return sections.join('\n');
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* CLI-specific setup for Claude Code
|
|
238
|
+
*/
|
|
239
|
+
async setupCliSpecific(config) {
|
|
240
|
+
// Ensure .claude directory structure
|
|
241
|
+
const clauePath = path.join(this.projectDir, this.cliFolder);
|
|
242
|
+
|
|
243
|
+
// Create standard directories
|
|
244
|
+
const dirs = ['commands', 'docs', 'rules', 'skills'];
|
|
245
|
+
for (const dir of dirs) {
|
|
246
|
+
const dirPath = path.join(clauePath, dir);
|
|
247
|
+
if (!fs.existsSync(dirPath)) {
|
|
248
|
+
fs.mkdirSync(dirPath, { recursive: true });
|
|
249
|
+
this.log(`Created ${this.cliFolder}/${dir}/`);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// Copy commands from .workflow/commands if they exist
|
|
254
|
+
const workflowCommands = path.join(this.projectDir, this.workflowDir, 'commands');
|
|
255
|
+
const claudeCommands = path.join(clauePath, 'commands');
|
|
256
|
+
|
|
257
|
+
if (fs.existsSync(workflowCommands)) {
|
|
258
|
+
const commands = fs.readdirSync(workflowCommands).filter(f => f.endsWith('.md'));
|
|
259
|
+
for (const cmd of commands) {
|
|
260
|
+
fs.copyFileSync(
|
|
261
|
+
path.join(workflowCommands, cmd),
|
|
262
|
+
path.join(claudeCommands, cmd)
|
|
263
|
+
);
|
|
264
|
+
this.log(`Synced command: ${cmd}`);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// Ensure hot-reload compatibility: skills in .claude/skills
|
|
269
|
+
// This is already handled by syncSkills() in base class
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Get nested value from object using dot notation
|
|
274
|
+
*/
|
|
275
|
+
getNestedValue(obj, path) {
|
|
276
|
+
return path.split('.').reduce((acc, part) => acc && acc[part], obj);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Generate settings.local.json with wildcard permissions
|
|
281
|
+
* Claude Code 2.1.0+ supports wildcards like Bash(npm *)
|
|
282
|
+
*/
|
|
283
|
+
generateSettings(config) {
|
|
284
|
+
const projectDir = this.projectDir;
|
|
285
|
+
|
|
286
|
+
// Base wildcard permissions - covers most common use cases
|
|
287
|
+
const wildcardPermissions = [
|
|
288
|
+
// Package managers
|
|
289
|
+
'Bash(npm *)',
|
|
290
|
+
'Bash(npx *)',
|
|
291
|
+
'Bash(yarn *)',
|
|
292
|
+
'Bash(pnpm *)',
|
|
293
|
+
'Bash(pip *)',
|
|
294
|
+
'Bash(python *)',
|
|
295
|
+
'Bash(python3 *)',
|
|
296
|
+
|
|
297
|
+
// Git operations
|
|
298
|
+
'Bash(git status)',
|
|
299
|
+
'Bash(git status *)',
|
|
300
|
+
'Bash(git diff *)',
|
|
301
|
+
'Bash(git log *)',
|
|
302
|
+
'Bash(git branch *)',
|
|
303
|
+
'Bash(git checkout *)',
|
|
304
|
+
'Bash(git add *)',
|
|
305
|
+
'Bash(git commit *)',
|
|
306
|
+
'Bash(git push *)',
|
|
307
|
+
'Bash(git pull *)',
|
|
308
|
+
'Bash(git fetch *)',
|
|
309
|
+
'Bash(git reset *)',
|
|
310
|
+
'Bash(git restore *)',
|
|
311
|
+
'Bash(git show *)',
|
|
312
|
+
'Bash(git rm *)',
|
|
313
|
+
'Bash(git ls-files *)',
|
|
314
|
+
'Bash(git check-ignore *)',
|
|
315
|
+
|
|
316
|
+
// GitHub CLI
|
|
317
|
+
'Bash(gh pr *)',
|
|
318
|
+
'Bash(gh issue *)',
|
|
319
|
+
'Bash(gh api *)',
|
|
320
|
+
|
|
321
|
+
// Flow scripts
|
|
322
|
+
`Bash(${path.join(projectDir, 'scripts/flow')} *)`,
|
|
323
|
+
'Bash(./scripts/flow *)',
|
|
324
|
+
'Bash(./scripts/flow)',
|
|
325
|
+
|
|
326
|
+
// Common utilities
|
|
327
|
+
'Bash(ls *)',
|
|
328
|
+
'Bash(tree *)',
|
|
329
|
+
'Bash(cat *)',
|
|
330
|
+
'Bash(head *)',
|
|
331
|
+
'Bash(tail *)',
|
|
332
|
+
'Bash(wc *)',
|
|
333
|
+
'Bash(grep *)',
|
|
334
|
+
'Bash(find *)',
|
|
335
|
+
'Bash(chmod +x *)', // Only make executable, not arbitrary permissions
|
|
336
|
+
'Bash(node *)',
|
|
337
|
+
'Bash(bash *)',
|
|
338
|
+
'Bash(open *)',
|
|
339
|
+
'Bash(test *)',
|
|
340
|
+
|
|
341
|
+
// AWS - Read-only and safe operations
|
|
342
|
+
'Bash(aws s3 ls *)',
|
|
343
|
+
'Bash(aws s3 cp *)',
|
|
344
|
+
'Bash(aws sts get-caller-identity)',
|
|
345
|
+
'Bash(aws sts get-caller-identity *)',
|
|
346
|
+
'Bash(aws configure list)',
|
|
347
|
+
'Bash(aws --version)',
|
|
348
|
+
|
|
349
|
+
// Terraform - Safe planning and validation operations
|
|
350
|
+
'Bash(terraform plan *)',
|
|
351
|
+
'Bash(terraform fmt *)',
|
|
352
|
+
'Bash(terraform validate *)',
|
|
353
|
+
'Bash(terraform init *)',
|
|
354
|
+
'Bash(terraform show *)',
|
|
355
|
+
'Bash(terraform output *)',
|
|
356
|
+
'Bash(terraform version)',
|
|
357
|
+
|
|
358
|
+
// Database - Project-scoped
|
|
359
|
+
'Bash(sqlite3 *.db *)',
|
|
360
|
+
'Bash(sqlite3 *.sqlite *)',
|
|
361
|
+
|
|
362
|
+
// Web fetch domains
|
|
363
|
+
'WebFetch(domain:github.com)',
|
|
364
|
+
'WebFetch(domain:api.github.com)',
|
|
365
|
+
'WebFetch(domain:raw.githubusercontent.com)',
|
|
366
|
+
|
|
367
|
+
// Web search
|
|
368
|
+
'WebSearch',
|
|
369
|
+
|
|
370
|
+
// Skills
|
|
371
|
+
'Skill(wogi-*)',
|
|
372
|
+
];
|
|
373
|
+
|
|
374
|
+
// Additional domains from config
|
|
375
|
+
const additionalDomains = config.permissions?.allowedDomains || [];
|
|
376
|
+
for (const domain of additionalDomains) {
|
|
377
|
+
wildcardPermissions.push(`WebFetch(domain:${domain})`);
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
// Additional custom permissions from config (for advanced users)
|
|
381
|
+
const customPermissions = config.permissions?.custom || [];
|
|
382
|
+
for (const perm of customPermissions) {
|
|
383
|
+
if (!wildcardPermissions.includes(perm)) {
|
|
384
|
+
wildcardPermissions.push(perm);
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
return {
|
|
389
|
+
permissions: {
|
|
390
|
+
allow: wildcardPermissions,
|
|
391
|
+
},
|
|
392
|
+
respectGitignore: true,
|
|
393
|
+
_wogiFlowManaged: true,
|
|
394
|
+
_wogiFlowVersion: '2.0.0',
|
|
395
|
+
_generatedAt: new Date().toISOString(),
|
|
396
|
+
};
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
/**
|
|
400
|
+
* Sync settings.local.json with wildcard permissions
|
|
401
|
+
* Preserves hooks and other custom settings
|
|
402
|
+
*/
|
|
403
|
+
syncSettings(config) {
|
|
404
|
+
const settingsPath = path.join(this.projectDir, this.cliFolder, 'settings.local.json');
|
|
405
|
+
|
|
406
|
+
let existingSettings = {};
|
|
407
|
+
if (fs.existsSync(settingsPath)) {
|
|
408
|
+
try {
|
|
409
|
+
existingSettings = JSON.parse(fs.readFileSync(settingsPath, 'utf-8'));
|
|
410
|
+
} catch (e) {
|
|
411
|
+
this.log(`Warning: Could not parse existing settings.local.json`);
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
const newSettings = this.generateSettings(config);
|
|
416
|
+
|
|
417
|
+
// Merge: keep existing hooks, use new permissions
|
|
418
|
+
const mergedSettings = {
|
|
419
|
+
permissions: newSettings.permissions,
|
|
420
|
+
respectGitignore: newSettings.respectGitignore,
|
|
421
|
+
hooks: existingSettings.hooks || {},
|
|
422
|
+
_wogiFlowManaged: newSettings._wogiFlowManaged,
|
|
423
|
+
_wogiFlowVersion: newSettings._wogiFlowVersion,
|
|
424
|
+
_generatedAt: newSettings._generatedAt,
|
|
425
|
+
};
|
|
426
|
+
|
|
427
|
+
fs.writeFileSync(settingsPath, JSON.stringify(mergedSettings, null, 2));
|
|
428
|
+
this.log(`Synced settings.local.json with wildcard permissions (${newSettings.permissions.allow.length} rules)`);
|
|
429
|
+
|
|
430
|
+
return mergedSettings;
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
module.exports = ClaudeBridge;
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI Bridges - Entry Point
|
|
3
|
+
*
|
|
4
|
+
* Provides a unified interface for loading and using CLI bridges.
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* const { getBridge, syncBridge } = require('./.workflow/bridges');
|
|
8
|
+
*
|
|
9
|
+
* // Get the bridge for current CLI type
|
|
10
|
+
* const bridge = getBridge();
|
|
11
|
+
*
|
|
12
|
+
* // Sync files from .workflow/ to CLI-specific folder
|
|
13
|
+
* await syncBridge();
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
const fs = require('fs');
|
|
17
|
+
const path = require('path');
|
|
18
|
+
|
|
19
|
+
// Lazy-load bridges to avoid circular dependencies
|
|
20
|
+
let bridges = null;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Load available bridge implementations
|
|
24
|
+
*/
|
|
25
|
+
function loadBridges() {
|
|
26
|
+
if (bridges) return bridges;
|
|
27
|
+
|
|
28
|
+
bridges = {
|
|
29
|
+
'claude-code': () => require('./claude-bridge'),
|
|
30
|
+
// Add more bridges as they are implemented
|
|
31
|
+
// 'gemini-cli': () => require('./gemini-bridge'),
|
|
32
|
+
// 'opencode': () => require('./opencode-bridge'),
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
return bridges;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Read CLI type from config
|
|
40
|
+
* @param {string} projectDir - Project root directory
|
|
41
|
+
* @returns {string} CLI type (defaults to 'claude-code')
|
|
42
|
+
*/
|
|
43
|
+
function getCliType(projectDir = process.cwd()) {
|
|
44
|
+
const configPath = path.join(projectDir, '.workflow', 'config.json');
|
|
45
|
+
|
|
46
|
+
if (!fs.existsSync(configPath)) {
|
|
47
|
+
return 'claude-code'; // Default
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
try {
|
|
51
|
+
const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
52
|
+
return config.cli?.type || 'claude-code';
|
|
53
|
+
} catch {
|
|
54
|
+
return 'claude-code';
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Get the bridge instance for the current CLI type
|
|
60
|
+
* @param {Object} options - Options to pass to bridge constructor
|
|
61
|
+
* @param {string} options.projectDir - Project root directory
|
|
62
|
+
* @param {boolean} options.verbose - Enable verbose logging
|
|
63
|
+
* @returns {BaseBridge} Bridge instance
|
|
64
|
+
*/
|
|
65
|
+
function getBridge(options = {}) {
|
|
66
|
+
const projectDir = options.projectDir || process.cwd();
|
|
67
|
+
const cliType = getCliType(projectDir);
|
|
68
|
+
|
|
69
|
+
loadBridges();
|
|
70
|
+
|
|
71
|
+
const BridgeLoader = bridges[cliType];
|
|
72
|
+
if (!BridgeLoader) {
|
|
73
|
+
// If no specific bridge exists, return null (manual mode)
|
|
74
|
+
console.warn(`No bridge available for CLI type: ${cliType}`);
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const BridgeClass = BridgeLoader();
|
|
79
|
+
return new BridgeClass({
|
|
80
|
+
projectDir,
|
|
81
|
+
verbose: options.verbose || false
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Sync the current CLI bridge
|
|
87
|
+
* @param {Object} options - Options
|
|
88
|
+
* @returns {Object} Sync result
|
|
89
|
+
*/
|
|
90
|
+
async function syncBridge(options = {}) {
|
|
91
|
+
const bridge = getBridge(options);
|
|
92
|
+
|
|
93
|
+
if (!bridge) {
|
|
94
|
+
return {
|
|
95
|
+
success: false,
|
|
96
|
+
error: 'No bridge available for current CLI type',
|
|
97
|
+
cliType: getCliType(options.projectDir)
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return await bridge.sync();
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* List available bridge types
|
|
106
|
+
* @returns {string[]} Array of available CLI types
|
|
107
|
+
*/
|
|
108
|
+
function listAvailableBridges() {
|
|
109
|
+
loadBridges();
|
|
110
|
+
return Object.keys(bridges);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Check if a bridge is available for the given CLI type
|
|
115
|
+
* @param {string} cliType - CLI type to check
|
|
116
|
+
* @returns {boolean}
|
|
117
|
+
*/
|
|
118
|
+
function isBridgeAvailable(cliType) {
|
|
119
|
+
loadBridges();
|
|
120
|
+
return cliType in bridges;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
module.exports = {
|
|
124
|
+
getBridge,
|
|
125
|
+
syncBridge,
|
|
126
|
+
getCliType,
|
|
127
|
+
listAvailableBridges,
|
|
128
|
+
isBridgeAvailable,
|
|
129
|
+
BaseBridge: require('./base-bridge')
|
|
130
|
+
};
|