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,482 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Wogi Flow - Project Context Initializer
|
|
5
|
+
*
|
|
6
|
+
* Creates and manages project context files:
|
|
7
|
+
* - stack.md - Technology stack (auto-detected + human verified)
|
|
8
|
+
* - constraints.md - Immutable rules (human controlled)
|
|
9
|
+
* - conventions.md - Coding patterns (AI can propose updates)
|
|
10
|
+
*
|
|
11
|
+
* Usage:
|
|
12
|
+
* flow context-init # Initialize context files
|
|
13
|
+
* flow context-init --rescan # Rescan and update stack.md
|
|
14
|
+
* flow context show # Show all context
|
|
15
|
+
* flow context stack # Show stack.md
|
|
16
|
+
* flow context constraints # Show constraints.md
|
|
17
|
+
* flow context conventions # Show conventions.md
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
const fs = require('fs');
|
|
21
|
+
const path = require('path');
|
|
22
|
+
const { getProjectRoot, colors: c } = require('./flow-utils');
|
|
23
|
+
|
|
24
|
+
const PROJECT_ROOT = getProjectRoot();
|
|
25
|
+
const WORKFLOW_DIR = path.join(PROJECT_ROOT, '.workflow');
|
|
26
|
+
const CONTEXT_DIR = path.join(WORKFLOW_DIR, 'context');
|
|
27
|
+
const TEMPLATES_DIR = path.join(__dirname, '..', 'templates', 'context');
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Detect technology stack from project files
|
|
31
|
+
*/
|
|
32
|
+
function detectStack() {
|
|
33
|
+
const stack = {
|
|
34
|
+
language: null,
|
|
35
|
+
languageVersion: null,
|
|
36
|
+
runtime: null,
|
|
37
|
+
packageManager: null,
|
|
38
|
+
frameworks: {
|
|
39
|
+
frontend: null,
|
|
40
|
+
backend: null,
|
|
41
|
+
fullStack: null
|
|
42
|
+
},
|
|
43
|
+
testing: null,
|
|
44
|
+
linting: null,
|
|
45
|
+
formatting: null,
|
|
46
|
+
typeChecking: null,
|
|
47
|
+
bundler: null,
|
|
48
|
+
database: null,
|
|
49
|
+
orm: null,
|
|
50
|
+
dependencies: {}
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
// Check package.json for Node.js projects
|
|
54
|
+
const packageJsonPath = path.join(PROJECT_ROOT, 'package.json');
|
|
55
|
+
if (fs.existsSync(packageJsonPath)) {
|
|
56
|
+
try {
|
|
57
|
+
const pkg = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
|
|
58
|
+
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
59
|
+
|
|
60
|
+
stack.runtime = 'Node.js';
|
|
61
|
+
|
|
62
|
+
// Detect language
|
|
63
|
+
if (deps.typescript) {
|
|
64
|
+
stack.language = 'TypeScript';
|
|
65
|
+
stack.languageVersion = deps.typescript.replace(/[\^~]/g, '');
|
|
66
|
+
stack.typeChecking = 'TypeScript';
|
|
67
|
+
} else {
|
|
68
|
+
stack.language = 'JavaScript';
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Detect frameworks
|
|
72
|
+
if (deps.next) {
|
|
73
|
+
stack.frameworks.fullStack = `Next.js ${deps.next.replace(/[\^~]/g, '')}`;
|
|
74
|
+
} else if (deps.nuxt) {
|
|
75
|
+
stack.frameworks.fullStack = `Nuxt ${deps.nuxt.replace(/[\^~]/g, '')}`;
|
|
76
|
+
} else if (deps['@sveltejs/kit']) {
|
|
77
|
+
stack.frameworks.fullStack = 'SvelteKit';
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (deps.react) {
|
|
81
|
+
stack.frameworks.frontend = `React ${deps.react.replace(/[\^~]/g, '')}`;
|
|
82
|
+
} else if (deps.vue) {
|
|
83
|
+
stack.frameworks.frontend = `Vue ${deps.vue.replace(/[\^~]/g, '')}`;
|
|
84
|
+
} else if (deps.svelte) {
|
|
85
|
+
stack.frameworks.frontend = `Svelte ${deps.svelte.replace(/[\^~]/g, '')}`;
|
|
86
|
+
} else if (deps['@angular/core']) {
|
|
87
|
+
stack.frameworks.frontend = `Angular ${deps['@angular/core'].replace(/[\^~]/g, '')}`;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (deps.express) {
|
|
91
|
+
stack.frameworks.backend = `Express ${deps.express.replace(/[\^~]/g, '')}`;
|
|
92
|
+
} else if (deps.fastify) {
|
|
93
|
+
stack.frameworks.backend = `Fastify ${deps.fastify.replace(/[\^~]/g, '')}`;
|
|
94
|
+
} else if (deps['@nestjs/core']) {
|
|
95
|
+
stack.frameworks.backend = 'NestJS';
|
|
96
|
+
} else if (deps.hono) {
|
|
97
|
+
stack.frameworks.backend = `Hono ${deps.hono.replace(/[\^~]/g, '')}`;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Detect testing
|
|
101
|
+
if (deps.vitest) {
|
|
102
|
+
stack.testing = 'Vitest';
|
|
103
|
+
} else if (deps.jest) {
|
|
104
|
+
stack.testing = 'Jest';
|
|
105
|
+
} else if (deps.mocha) {
|
|
106
|
+
stack.testing = 'Mocha';
|
|
107
|
+
} else if (deps['@playwright/test']) {
|
|
108
|
+
stack.testing = 'Playwright';
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Detect linting
|
|
112
|
+
if (deps['@biomejs/biome'] || deps.biome) {
|
|
113
|
+
stack.linting = 'Biome';
|
|
114
|
+
stack.formatting = 'Biome';
|
|
115
|
+
} else if (deps.eslint) {
|
|
116
|
+
stack.linting = 'ESLint';
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Detect formatting
|
|
120
|
+
if (!stack.formatting && deps.prettier) {
|
|
121
|
+
stack.formatting = 'Prettier';
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Detect bundler
|
|
125
|
+
if (deps.vite) {
|
|
126
|
+
stack.bundler = 'Vite';
|
|
127
|
+
} else if (deps.webpack) {
|
|
128
|
+
stack.bundler = 'Webpack';
|
|
129
|
+
} else if (deps.esbuild) {
|
|
130
|
+
stack.bundler = 'esbuild';
|
|
131
|
+
} else if (deps.rollup) {
|
|
132
|
+
stack.bundler = 'Rollup';
|
|
133
|
+
} else if (deps.parcel) {
|
|
134
|
+
stack.bundler = 'Parcel';
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Detect database/ORM
|
|
138
|
+
if (deps.prisma || deps['@prisma/client']) {
|
|
139
|
+
stack.orm = 'Prisma';
|
|
140
|
+
} else if (deps.drizzle || deps['drizzle-orm']) {
|
|
141
|
+
stack.orm = 'Drizzle';
|
|
142
|
+
} else if (deps.typeorm) {
|
|
143
|
+
stack.orm = 'TypeORM';
|
|
144
|
+
} else if (deps.sequelize) {
|
|
145
|
+
stack.orm = 'Sequelize';
|
|
146
|
+
} else if (deps.mongoose) {
|
|
147
|
+
stack.orm = 'Mongoose';
|
|
148
|
+
stack.database = 'MongoDB';
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (deps.pg || deps.postgres) {
|
|
152
|
+
stack.database = 'PostgreSQL';
|
|
153
|
+
} else if (deps.mysql2 || deps.mysql) {
|
|
154
|
+
stack.database = 'MySQL';
|
|
155
|
+
} else if (deps['better-sqlite3'] || deps.sqlite3) {
|
|
156
|
+
stack.database = 'SQLite';
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Store key dependencies
|
|
160
|
+
const keyDeps = ['react', 'vue', 'svelte', 'next', 'express', 'fastify',
|
|
161
|
+
'prisma', 'typescript', 'vite', 'tailwindcss', 'zod', 'trpc'];
|
|
162
|
+
for (const dep of keyDeps) {
|
|
163
|
+
if (deps[dep]) {
|
|
164
|
+
stack.dependencies[dep] = deps[dep].replace(/[\^~]/g, '');
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
} catch (err) {
|
|
168
|
+
console.error(`${c.yellow}Warning: Could not parse package.json${c.reset}`);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Detect package manager
|
|
173
|
+
if (fs.existsSync(path.join(PROJECT_ROOT, 'pnpm-lock.yaml'))) {
|
|
174
|
+
stack.packageManager = 'pnpm';
|
|
175
|
+
} else if (fs.existsSync(path.join(PROJECT_ROOT, 'yarn.lock'))) {
|
|
176
|
+
stack.packageManager = 'yarn';
|
|
177
|
+
} else if (fs.existsSync(path.join(PROJECT_ROOT, 'bun.lockb'))) {
|
|
178
|
+
stack.packageManager = 'bun';
|
|
179
|
+
stack.runtime = 'Bun';
|
|
180
|
+
} else if (fs.existsSync(path.join(PROJECT_ROOT, 'package-lock.json'))) {
|
|
181
|
+
stack.packageManager = 'npm';
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Check for Python projects
|
|
185
|
+
const requirementsPath = path.join(PROJECT_ROOT, 'requirements.txt');
|
|
186
|
+
const pyprojectPath = path.join(PROJECT_ROOT, 'pyproject.toml');
|
|
187
|
+
if (fs.existsSync(requirementsPath) || fs.existsSync(pyprojectPath)) {
|
|
188
|
+
stack.language = 'Python';
|
|
189
|
+
stack.runtime = 'Python';
|
|
190
|
+
|
|
191
|
+
if (fs.existsSync(path.join(PROJECT_ROOT, 'poetry.lock'))) {
|
|
192
|
+
stack.packageManager = 'Poetry';
|
|
193
|
+
} else if (fs.existsSync(path.join(PROJECT_ROOT, 'Pipfile.lock'))) {
|
|
194
|
+
stack.packageManager = 'Pipenv';
|
|
195
|
+
} else {
|
|
196
|
+
stack.packageManager = 'pip';
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Try to detect Python frameworks
|
|
200
|
+
const requirements = fs.existsSync(requirementsPath)
|
|
201
|
+
? fs.readFileSync(requirementsPath, 'utf-8')
|
|
202
|
+
: '';
|
|
203
|
+
|
|
204
|
+
if (requirements.includes('fastapi') || requirements.includes('FastAPI')) {
|
|
205
|
+
stack.frameworks.backend = 'FastAPI';
|
|
206
|
+
} else if (requirements.includes('django') || requirements.includes('Django')) {
|
|
207
|
+
stack.frameworks.backend = 'Django';
|
|
208
|
+
} else if (requirements.includes('flask') || requirements.includes('Flask')) {
|
|
209
|
+
stack.frameworks.backend = 'Flask';
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
if (requirements.includes('pytest')) {
|
|
213
|
+
stack.testing = 'pytest';
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// Check for Rust projects
|
|
218
|
+
const cargoPath = path.join(PROJECT_ROOT, 'Cargo.toml');
|
|
219
|
+
if (fs.existsSync(cargoPath)) {
|
|
220
|
+
stack.language = 'Rust';
|
|
221
|
+
stack.runtime = 'Rust';
|
|
222
|
+
stack.packageManager = 'Cargo';
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// Check for Go projects
|
|
226
|
+
const goModPath = path.join(PROJECT_ROOT, 'go.mod');
|
|
227
|
+
if (fs.existsSync(goModPath)) {
|
|
228
|
+
stack.language = 'Go';
|
|
229
|
+
stack.runtime = 'Go';
|
|
230
|
+
stack.packageManager = 'Go Modules';
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
return stack;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Generate stack.md content from detected stack
|
|
238
|
+
*/
|
|
239
|
+
function generateStackContent(stack) {
|
|
240
|
+
const timestamp = new Date().toISOString().slice(0, 10);
|
|
241
|
+
|
|
242
|
+
let content = `# Technology Stack
|
|
243
|
+
|
|
244
|
+
Auto-detected on ${timestamp}. Please verify and update as needed.
|
|
245
|
+
|
|
246
|
+
---
|
|
247
|
+
|
|
248
|
+
## Runtime
|
|
249
|
+
- **Language**: ${stack.language || 'Not detected'}${stack.languageVersion ? ` ${stack.languageVersion}` : ''}
|
|
250
|
+
- **Runtime**: ${stack.runtime || 'Not detected'}
|
|
251
|
+
- **Package Manager**: ${stack.packageManager || 'Not detected'}
|
|
252
|
+
|
|
253
|
+
## Frameworks
|
|
254
|
+
- **Frontend**: ${stack.frameworks.frontend || 'None'}
|
|
255
|
+
- **Backend**: ${stack.frameworks.backend || 'None'}
|
|
256
|
+
- **Full-Stack**: ${stack.frameworks.fullStack || 'None'}
|
|
257
|
+
|
|
258
|
+
## Build & Tooling
|
|
259
|
+
- **Bundler**: ${stack.bundler || 'Not detected'}
|
|
260
|
+
- **Testing**: ${stack.testing || 'Not detected'}
|
|
261
|
+
- **Linting**: ${stack.linting || 'Not detected'}
|
|
262
|
+
- **Formatting**: ${stack.formatting || 'Not detected'}
|
|
263
|
+
- **Type Checking**: ${stack.typeChecking || 'None'}
|
|
264
|
+
|
|
265
|
+
## Infrastructure
|
|
266
|
+
- **Database**: ${stack.database || 'Not detected'}
|
|
267
|
+
- **ORM/ODM**: ${stack.orm || 'Not detected'}
|
|
268
|
+
|
|
269
|
+
`;
|
|
270
|
+
|
|
271
|
+
// Add key dependencies
|
|
272
|
+
const depEntries = Object.entries(stack.dependencies);
|
|
273
|
+
if (depEntries.length > 0) {
|
|
274
|
+
content += `## Key Dependencies
|
|
275
|
+
|
|
276
|
+
| Dependency | Version |
|
|
277
|
+
|------------|---------|
|
|
278
|
+
`;
|
|
279
|
+
for (const [name, version] of depEntries) {
|
|
280
|
+
content += `| ${name} | ${version} |\n`;
|
|
281
|
+
}
|
|
282
|
+
content += '\n';
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
content += `---
|
|
286
|
+
|
|
287
|
+
*Last updated: ${timestamp}*
|
|
288
|
+
*Updated by: auto-detect*
|
|
289
|
+
`;
|
|
290
|
+
|
|
291
|
+
return content;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* Initialize context files
|
|
296
|
+
*/
|
|
297
|
+
function initContext(options = {}) {
|
|
298
|
+
// Create context directory
|
|
299
|
+
if (!fs.existsSync(CONTEXT_DIR)) {
|
|
300
|
+
fs.mkdirSync(CONTEXT_DIR, { recursive: true });
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
const results = {
|
|
304
|
+
stack: false,
|
|
305
|
+
constraints: false,
|
|
306
|
+
conventions: false
|
|
307
|
+
};
|
|
308
|
+
|
|
309
|
+
// Generate stack.md
|
|
310
|
+
const stackPath = path.join(CONTEXT_DIR, 'stack.md');
|
|
311
|
+
if (!fs.existsSync(stackPath) || options.rescan) {
|
|
312
|
+
const stack = detectStack();
|
|
313
|
+
const content = generateStackContent(stack);
|
|
314
|
+
fs.writeFileSync(stackPath, content);
|
|
315
|
+
results.stack = true;
|
|
316
|
+
console.log(`${c.green}✅ ${options.rescan ? 'Updated' : 'Created'} stack.md${c.reset}`);
|
|
317
|
+
} else {
|
|
318
|
+
console.log(`${c.dim} stack.md already exists (use --rescan to update)${c.reset}`);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// Copy constraints.md template
|
|
322
|
+
const constraintsPath = path.join(CONTEXT_DIR, 'constraints.md');
|
|
323
|
+
if (!fs.existsSync(constraintsPath)) {
|
|
324
|
+
const templatePath = path.join(TEMPLATES_DIR, 'constraints.md');
|
|
325
|
+
if (fs.existsSync(templatePath)) {
|
|
326
|
+
let content = fs.readFileSync(templatePath, 'utf-8');
|
|
327
|
+
content = content.replace(/\{\{date\}\}/g, new Date().toISOString().slice(0, 10));
|
|
328
|
+
fs.writeFileSync(constraintsPath, content);
|
|
329
|
+
results.constraints = true;
|
|
330
|
+
console.log(`${c.green}✅ Created constraints.md${c.reset}`);
|
|
331
|
+
}
|
|
332
|
+
} else {
|
|
333
|
+
console.log(`${c.dim} constraints.md already exists${c.reset}`);
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
// Copy conventions.md template
|
|
337
|
+
const conventionsPath = path.join(CONTEXT_DIR, 'conventions.md');
|
|
338
|
+
if (!fs.existsSync(conventionsPath)) {
|
|
339
|
+
const templatePath = path.join(TEMPLATES_DIR, 'conventions.md');
|
|
340
|
+
if (fs.existsSync(templatePath)) {
|
|
341
|
+
fs.copyFileSync(templatePath, conventionsPath);
|
|
342
|
+
results.conventions = true;
|
|
343
|
+
console.log(`${c.green}✅ Created conventions.md${c.reset}`);
|
|
344
|
+
}
|
|
345
|
+
} else {
|
|
346
|
+
console.log(`${c.dim} conventions.md already exists${c.reset}`);
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
return results;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
* Show context file contents
|
|
354
|
+
*/
|
|
355
|
+
function showContext(file = null) {
|
|
356
|
+
const files = file
|
|
357
|
+
? [file]
|
|
358
|
+
: ['stack.md', 'constraints.md', 'conventions.md'];
|
|
359
|
+
|
|
360
|
+
for (const f of files) {
|
|
361
|
+
const filePath = path.join(CONTEXT_DIR, f.endsWith('.md') ? f : `${f}.md`);
|
|
362
|
+
if (fs.existsSync(filePath)) {
|
|
363
|
+
console.log(`\n${c.cyan}${c.bold}=== ${f} ===${c.reset}\n`);
|
|
364
|
+
console.log(fs.readFileSync(filePath, 'utf-8'));
|
|
365
|
+
} else {
|
|
366
|
+
console.log(`${c.yellow}File not found: ${f}${c.reset}`);
|
|
367
|
+
console.log(`${c.dim}Run "flow context-init" to create context files${c.reset}`);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* Load all context for LLM prompts
|
|
374
|
+
*/
|
|
375
|
+
function loadProjectContext() {
|
|
376
|
+
const context = {};
|
|
377
|
+
const files = ['stack.md', 'constraints.md', 'conventions.md'];
|
|
378
|
+
|
|
379
|
+
for (const file of files) {
|
|
380
|
+
const filePath = path.join(CONTEXT_DIR, file);
|
|
381
|
+
if (fs.existsSync(filePath)) {
|
|
382
|
+
const key = file.replace('.md', '');
|
|
383
|
+
context[key] = fs.readFileSync(filePath, 'utf-8');
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
return context;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
* Get context summary for prompts
|
|
392
|
+
*/
|
|
393
|
+
function getContextSummary() {
|
|
394
|
+
const context = loadProjectContext();
|
|
395
|
+
let summary = '';
|
|
396
|
+
|
|
397
|
+
if (context.stack) {
|
|
398
|
+
summary += '## Technology Stack\n' + context.stack + '\n\n';
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
if (context.constraints) {
|
|
402
|
+
summary += '## Project Constraints (MUST FOLLOW)\n' + context.constraints + '\n\n';
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
if (context.conventions) {
|
|
406
|
+
summary += '## Coding Conventions\n' + context.conventions + '\n\n';
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
return summary;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
// Module exports
|
|
413
|
+
module.exports = {
|
|
414
|
+
detectStack,
|
|
415
|
+
initContext,
|
|
416
|
+
showContext,
|
|
417
|
+
loadProjectContext,
|
|
418
|
+
getContextSummary
|
|
419
|
+
};
|
|
420
|
+
|
|
421
|
+
// CLI Handler
|
|
422
|
+
if (require.main === module) {
|
|
423
|
+
const args = process.argv.slice(2);
|
|
424
|
+
const command = args[0];
|
|
425
|
+
|
|
426
|
+
switch (command) {
|
|
427
|
+
case 'init':
|
|
428
|
+
case undefined: {
|
|
429
|
+
const rescan = args.includes('--rescan');
|
|
430
|
+
console.log(`${c.cyan}${c.bold}Initializing Project Context${c.reset}\n`);
|
|
431
|
+
initContext({ rescan });
|
|
432
|
+
console.log(`\n${c.dim}Context files created in .workflow/context/${c.reset}`);
|
|
433
|
+
break;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
case 'show': {
|
|
437
|
+
const file = args[1];
|
|
438
|
+
showContext(file);
|
|
439
|
+
break;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
case 'stack':
|
|
443
|
+
case 'constraints':
|
|
444
|
+
case 'conventions': {
|
|
445
|
+
showContext(command);
|
|
446
|
+
break;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
case 'detect': {
|
|
450
|
+
const stack = detectStack();
|
|
451
|
+
console.log(JSON.stringify(stack, null, 2));
|
|
452
|
+
break;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
case '--help':
|
|
456
|
+
case '-h': {
|
|
457
|
+
console.log(`
|
|
458
|
+
${c.cyan}Wogi Flow - Project Context Manager${c.reset}
|
|
459
|
+
|
|
460
|
+
${c.bold}Usage:${c.reset}
|
|
461
|
+
flow context-init Initialize context files
|
|
462
|
+
flow context-init --rescan Rescan and update stack.md
|
|
463
|
+
flow context show [file] Show context file(s)
|
|
464
|
+
flow context stack Show stack.md
|
|
465
|
+
flow context constraints Show constraints.md
|
|
466
|
+
flow context conventions Show conventions.md
|
|
467
|
+
flow context detect Detect stack (JSON output)
|
|
468
|
+
|
|
469
|
+
${c.bold}Files:${c.reset}
|
|
470
|
+
stack.md Technology stack (auto-detected)
|
|
471
|
+
constraints.md Immutable rules (human-controlled)
|
|
472
|
+
conventions.md Coding patterns (AI can propose updates)
|
|
473
|
+
`);
|
|
474
|
+
break;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
default:
|
|
478
|
+
console.log(`${c.red}Unknown command: ${command}${c.reset}`);
|
|
479
|
+
console.log(`${c.dim}Run "flow context-init --help" for usage${c.reset}`);
|
|
480
|
+
process.exit(1);
|
|
481
|
+
}
|
|
482
|
+
}
|