vibe-me 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/LICENSE +21 -0
- package/README.md +161 -0
- package/bin/vibes.js +349 -0
- package/package.json +34 -0
- package/spec/VIBE_GUIDE.md +848 -0
- package/templates/architecture.md +42 -0
- package/templates/decisions.md +33 -0
- package/templates/entities.md +24 -0
- package/templates/flows.md +51 -0
- package/templates/purpose.md +33 -0
- package/templates/state.json +12 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
# vibes
|
|
2
|
+
|
|
3
|
+
**Every repository should contain a continuously maintained, AI-readable and human-readable model of itself.**
|
|
4
|
+
|
|
5
|
+
`vibes` creates a `.vibe/` folder in your project — 6 files that let any human or AI understand your codebase without reading the source code.
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
.vibe/
|
|
9
|
+
├── purpose.md — What is this? Who is it for? What does it NOT do?
|
|
10
|
+
├── architecture.md — Systems and how they connect (not files — systems)
|
|
11
|
+
├── flows.md — User journeys, step by step
|
|
12
|
+
├── entities.md — Important nouns and their relationships
|
|
13
|
+
├── decisions.md — Why things exist the way they do
|
|
14
|
+
└── state.json — Machine-readable project health snapshot
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Why?
|
|
18
|
+
|
|
19
|
+
Most repositories are impossible to understand without reading the source code. Documentation describes *how* things work but never captures:
|
|
20
|
+
|
|
21
|
+
- **Why** things exist (what alternatives were rejected?)
|
|
22
|
+
- **What** users actually do (step-by-step journeys, not component descriptions)
|
|
23
|
+
- **What** the important nouns are (domain entities, not class hierarchies)
|
|
24
|
+
- **What** the system *is* (intent, not implementation)
|
|
25
|
+
|
|
26
|
+
The `.vibe/` folder answers these questions. It describes **intent rather than implementation** — which means it's language-agnostic, framework-agnostic, and survives complete rewrites.
|
|
27
|
+
|
|
28
|
+
## Quick Start
|
|
29
|
+
|
|
30
|
+
### Option 1: npx (no install)
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
npx vibes init
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Option 2: Global install
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
npm install -g vibes
|
|
40
|
+
vibes init
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Option 3: Clone and run
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
git clone https://github.com/unlimitedinfinit/Vibes.git
|
|
47
|
+
cd your-project
|
|
48
|
+
node /path/to/Vibes/bin/vibes.js init
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
This creates a `.vibe/` folder with skeleton templates and a `VIBE_GUIDE.md` instruction file.
|
|
52
|
+
|
|
53
|
+
## Usage
|
|
54
|
+
|
|
55
|
+
### Initialize
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
cd your-project
|
|
59
|
+
vibes init
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Creates `.vibe/` with 6 skeleton files + the full guide. Auto-detects your project name from `package.json`, `Cargo.toml`, `go.mod`, or `pyproject.toml`.
|
|
63
|
+
|
|
64
|
+
### Fill it out (with your AI agent)
|
|
65
|
+
|
|
66
|
+
Point your AI coding agent at the project and tell it:
|
|
67
|
+
|
|
68
|
+
> "Read `.vibe/VIBE_GUIDE.md`, then analyze this codebase and fill out all the skeleton files in `.vibe/`. Ask me any questions you can't answer from the code."
|
|
69
|
+
|
|
70
|
+
The guide contains detailed instructions, examples across 6+ project types, anti-patterns, and a quality checklist.
|
|
71
|
+
|
|
72
|
+
### Validate
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
vibes check
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Checks that all 6 files exist, are non-empty, and pass quality heuristics:
|
|
79
|
+
- `purpose.md` has a "NOT do" section
|
|
80
|
+
- `decisions.md` has 2+ decisions
|
|
81
|
+
- `entities.md` has "What depends on it?" fields
|
|
82
|
+
- `flows.md` has 2+ user flows
|
|
83
|
+
- `state.json` is valid JSON and not stale (>30 days)
|
|
84
|
+
|
|
85
|
+
### Reset
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
vibes reset
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Deletes and recreates `.vibe/` with fresh skeletons.
|
|
92
|
+
|
|
93
|
+
## The Core Principle
|
|
94
|
+
|
|
95
|
+
> **Describe intent, not implementation.**
|
|
96
|
+
|
|
97
|
+
Every line in `.vibe/` should pass this test: *"Would this still be true if we rewrote the entire codebase in a different language?"*
|
|
98
|
+
|
|
99
|
+
- ✅ "We chose SQLite because the access pattern is <100 writes/hour"
|
|
100
|
+
- ❌ "The `DatabaseService` class has a `connect()` method"
|
|
101
|
+
- ✅ "User uploads document → AI analyzes → results displayed"
|
|
102
|
+
- ❌ "POST /api/documents calls `processDocument()` in `services/ai.ts`"
|
|
103
|
+
|
|
104
|
+
## The AI Update Protocol
|
|
105
|
+
|
|
106
|
+
Every time an AI agent touches a repository with `.vibe/`, the workflow is:
|
|
107
|
+
|
|
108
|
+
```
|
|
109
|
+
Read .vibe/ to understand the project
|
|
110
|
+
↓
|
|
111
|
+
Make code changes
|
|
112
|
+
↓
|
|
113
|
+
Update relevant .vibe/ files to reflect new understanding
|
|
114
|
+
↓
|
|
115
|
+
Commit code + .vibe changes together
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
The semantic model is a first-class citizen — not an afterthought.
|
|
119
|
+
|
|
120
|
+
## Works With
|
|
121
|
+
|
|
122
|
+
`.vibe/` is language-agnostic. It works for:
|
|
123
|
+
|
|
124
|
+
- Python, TypeScript, Go, Rust, C#, Java, C++, Swift
|
|
125
|
+
- React, Next.js, Django, FastAPI, Spring, Rails
|
|
126
|
+
- Unity, Unreal, Godot
|
|
127
|
+
- Embedded firmware, CLI tools, mobile apps, libraries
|
|
128
|
+
- Monorepos, microservices, serverless
|
|
129
|
+
|
|
130
|
+
Because it describes **what** and **why**, not **how**.
|
|
131
|
+
|
|
132
|
+
## Repository Structure
|
|
133
|
+
|
|
134
|
+
```
|
|
135
|
+
Vibes/
|
|
136
|
+
├── bin/vibes.js — CLI entry point (zero dependencies)
|
|
137
|
+
├── templates/ — Skeleton files copied into .vibe/
|
|
138
|
+
│ ├── purpose.md
|
|
139
|
+
│ ├── architecture.md
|
|
140
|
+
│ ├── flows.md
|
|
141
|
+
│ ├── entities.md
|
|
142
|
+
│ ├── decisions.md
|
|
143
|
+
│ └── state.json
|
|
144
|
+
├── spec/
|
|
145
|
+
│ └── VIBE_GUIDE.md — Full spec with examples and instructions
|
|
146
|
+
├── QUICK_START_PROMPT.md — Copy-paste prompt for AI agents
|
|
147
|
+
├── VIBE_GUIDE.md — Full spec (also at root for easy reading)
|
|
148
|
+
├── package.json
|
|
149
|
+
├── LICENSE — MIT
|
|
150
|
+
└── README.md — This file
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## License
|
|
154
|
+
|
|
155
|
+
MIT — use it, fork it, build on it.
|
|
156
|
+
|
|
157
|
+
## Contributing
|
|
158
|
+
|
|
159
|
+
The `.vibe` spec is version 1.0. After testing across 20+ repositories, we'll refine which information is always useful, which is noise, what AI can extract automatically, and what humans must provide.
|
|
160
|
+
|
|
161
|
+
If you create `.vibe/` for your project, open an issue and share what you learned.
|
package/bin/vibes.js
ADDED
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// vibes — Create a .vibe/ semantic layer for any project
|
|
4
|
+
// Zero dependencies. Single file. Works with npx.
|
|
5
|
+
|
|
6
|
+
const fs = require('fs');
|
|
7
|
+
const path = require('path');
|
|
8
|
+
|
|
9
|
+
// ─────────────────────────────────────────────
|
|
10
|
+
// Config
|
|
11
|
+
// ─────────────────────────────────────────────
|
|
12
|
+
|
|
13
|
+
const VIBE_DIR = '.vibe';
|
|
14
|
+
const TEMPLATES_DIR = path.join(__dirname, '..', 'templates');
|
|
15
|
+
const SPEC_DIR = path.join(__dirname, '..', 'spec');
|
|
16
|
+
|
|
17
|
+
const TEMPLATE_FILES = [
|
|
18
|
+
'purpose.md',
|
|
19
|
+
'architecture.md',
|
|
20
|
+
'flows.md',
|
|
21
|
+
'entities.md',
|
|
22
|
+
'decisions.md',
|
|
23
|
+
'state.json'
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
const SPEC_FILE = 'VIBE_GUIDE.md';
|
|
27
|
+
|
|
28
|
+
// ─────────────────────────────────────────────
|
|
29
|
+
// Colors (no dependencies — raw ANSI)
|
|
30
|
+
// ─────────────────────────────────────────────
|
|
31
|
+
|
|
32
|
+
const bold = (s) => `\x1b[1m${s}\x1b[0m`;
|
|
33
|
+
const green = (s) => `\x1b[32m${s}\x1b[0m`;
|
|
34
|
+
const cyan = (s) => `\x1b[36m${s}\x1b[0m`;
|
|
35
|
+
const yellow = (s) => `\x1b[33m${s}\x1b[0m`;
|
|
36
|
+
const dim = (s) => `\x1b[2m${s}\x1b[0m`;
|
|
37
|
+
const red = (s) => `\x1b[31m${s}\x1b[0m`;
|
|
38
|
+
|
|
39
|
+
// ─────────────────────────────────────────────
|
|
40
|
+
// Helpers
|
|
41
|
+
// ─────────────────────────────────────────────
|
|
42
|
+
|
|
43
|
+
function fileExists(filePath) {
|
|
44
|
+
try {
|
|
45
|
+
fs.accessSync(filePath);
|
|
46
|
+
return true;
|
|
47
|
+
} catch {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function copyFile(src, dest) {
|
|
53
|
+
const content = fs.readFileSync(src, 'utf-8');
|
|
54
|
+
fs.writeFileSync(dest, content, 'utf-8');
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function getProjectName(dir) {
|
|
58
|
+
// Try package.json
|
|
59
|
+
const pkgPath = path.join(dir, 'package.json');
|
|
60
|
+
if (fileExists(pkgPath)) {
|
|
61
|
+
try {
|
|
62
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
|
|
63
|
+
if (pkg.name) return pkg.name;
|
|
64
|
+
} catch {}
|
|
65
|
+
}
|
|
66
|
+
// Try Cargo.toml
|
|
67
|
+
const cargoPath = path.join(dir, 'Cargo.toml');
|
|
68
|
+
if (fileExists(cargoPath)) {
|
|
69
|
+
try {
|
|
70
|
+
const cargo = fs.readFileSync(cargoPath, 'utf-8');
|
|
71
|
+
const match = cargo.match(/^name\s*=\s*"(.+)"/m);
|
|
72
|
+
if (match) return match[1];
|
|
73
|
+
} catch {}
|
|
74
|
+
}
|
|
75
|
+
// Try go.mod
|
|
76
|
+
const goModPath = path.join(dir, 'go.mod');
|
|
77
|
+
if (fileExists(goModPath)) {
|
|
78
|
+
try {
|
|
79
|
+
const goMod = fs.readFileSync(goModPath, 'utf-8');
|
|
80
|
+
const match = goMod.match(/^module\s+(.+)/m);
|
|
81
|
+
if (match) return match[1].split('/').pop();
|
|
82
|
+
} catch {}
|
|
83
|
+
}
|
|
84
|
+
// Try pyproject.toml
|
|
85
|
+
const pyPath = path.join(dir, 'pyproject.toml');
|
|
86
|
+
if (fileExists(pyPath)) {
|
|
87
|
+
try {
|
|
88
|
+
const py = fs.readFileSync(pyPath, 'utf-8');
|
|
89
|
+
const match = py.match(/^name\s*=\s*"(.+)"/m);
|
|
90
|
+
if (match) return match[1];
|
|
91
|
+
} catch {}
|
|
92
|
+
}
|
|
93
|
+
// Fallback to directory name
|
|
94
|
+
return path.basename(dir);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function getNow() {
|
|
98
|
+
return new Date().toISOString();
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// ─────────────────────────────────────────────
|
|
102
|
+
// Commands
|
|
103
|
+
// ─────────────────────────────────────────────
|
|
104
|
+
|
|
105
|
+
function cmdInit(targetDir) {
|
|
106
|
+
const vibeDir = path.join(targetDir, VIBE_DIR);
|
|
107
|
+
const projectName = getProjectName(targetDir);
|
|
108
|
+
|
|
109
|
+
// Check if .vibe already exists
|
|
110
|
+
if (fileExists(vibeDir)) {
|
|
111
|
+
console.log(red('\n ✖ .vibe/ already exists in this directory.'));
|
|
112
|
+
console.log(dim(' Use "vibes reset" to overwrite, or edit files directly.\n'));
|
|
113
|
+
process.exit(1);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
console.log('');
|
|
117
|
+
console.log(bold(' ⚡ vibes init'));
|
|
118
|
+
console.log(dim(` Creating .vibe/ semantic layer for ${cyan(projectName)}`));
|
|
119
|
+
console.log('');
|
|
120
|
+
|
|
121
|
+
// Create .vibe directory
|
|
122
|
+
fs.mkdirSync(vibeDir, { recursive: true });
|
|
123
|
+
|
|
124
|
+
// Copy template files
|
|
125
|
+
let created = 0;
|
|
126
|
+
for (const file of TEMPLATE_FILES) {
|
|
127
|
+
const src = path.join(TEMPLATES_DIR, file);
|
|
128
|
+
const dest = path.join(vibeDir, file);
|
|
129
|
+
|
|
130
|
+
if (file === 'state.json') {
|
|
131
|
+
// Inject project name and timestamp into state.json
|
|
132
|
+
let content = fs.readFileSync(src, 'utf-8');
|
|
133
|
+
content = content.replace('PROJECT_NAME', projectName);
|
|
134
|
+
content = content.replace('TIMESTAMP', getNow());
|
|
135
|
+
fs.writeFileSync(dest, content, 'utf-8');
|
|
136
|
+
} else {
|
|
137
|
+
// Copy markdown templates as-is
|
|
138
|
+
copyFile(src, dest);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
console.log(green(' ✔ ') + dim('.vibe/') + file);
|
|
142
|
+
created++;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Copy the guide as a hidden instruction file inside .vibe
|
|
146
|
+
const guideSrc = path.join(SPEC_DIR, SPEC_FILE);
|
|
147
|
+
const guideDest = path.join(vibeDir, SPEC_FILE);
|
|
148
|
+
copyFile(guideSrc, guideDest);
|
|
149
|
+
console.log(green(' ✔ ') + dim('.vibe/') + SPEC_FILE + dim(' (agent instructions)'));
|
|
150
|
+
created++;
|
|
151
|
+
|
|
152
|
+
console.log('');
|
|
153
|
+
console.log(green(` ✔ Created ${created} files in .vibe/`));
|
|
154
|
+
console.log('');
|
|
155
|
+
console.log(bold(' Next steps:'));
|
|
156
|
+
console.log('');
|
|
157
|
+
console.log(' 1. Point your AI coding agent at this project');
|
|
158
|
+
console.log(' 2. Tell it:');
|
|
159
|
+
console.log('');
|
|
160
|
+
console.log(cyan(' "Read .vibe/VIBE_GUIDE.md, then analyze this codebase'));
|
|
161
|
+
console.log(cyan(' and fill out all the skeleton files in .vibe/'));
|
|
162
|
+
console.log(cyan(' Ask me any questions you can\'t answer from the code."'));
|
|
163
|
+
console.log('');
|
|
164
|
+
console.log(' 3. Review the output, commit to version control');
|
|
165
|
+
console.log('');
|
|
166
|
+
console.log(dim(' The guide contains full instructions, examples, and'));
|
|
167
|
+
console.log(dim(' quality checklists for the AI to follow.'));
|
|
168
|
+
console.log('');
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function cmdCheck(targetDir) {
|
|
172
|
+
const vibeDir = path.join(targetDir, VIBE_DIR);
|
|
173
|
+
|
|
174
|
+
if (!fileExists(vibeDir)) {
|
|
175
|
+
console.log(red('\n ✖ No .vibe/ folder found. Run "vibes init" first.\n'));
|
|
176
|
+
process.exit(1);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
console.log('');
|
|
180
|
+
console.log(bold(' 🔍 vibes check'));
|
|
181
|
+
console.log('');
|
|
182
|
+
|
|
183
|
+
let passed = 0;
|
|
184
|
+
let failed = 0;
|
|
185
|
+
let warnings = 0;
|
|
186
|
+
|
|
187
|
+
// Check each file exists and is non-empty
|
|
188
|
+
for (const file of TEMPLATE_FILES) {
|
|
189
|
+
const filePath = path.join(vibeDir, file);
|
|
190
|
+
if (!fileExists(filePath)) {
|
|
191
|
+
console.log(red(' ✖ ') + `${file} — missing`);
|
|
192
|
+
failed++;
|
|
193
|
+
continue;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const content = fs.readFileSync(filePath, 'utf-8').trim();
|
|
197
|
+
const lines = content.split('\n').length;
|
|
198
|
+
|
|
199
|
+
if (lines < 5) {
|
|
200
|
+
console.log(yellow(' ⚠ ') + `${file} — exists but looks empty (${lines} lines)`);
|
|
201
|
+
warnings++;
|
|
202
|
+
continue;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// File-specific checks
|
|
206
|
+
if (file === 'purpose.md') {
|
|
207
|
+
if (!content.includes('NOT do') && !content.includes('not do') && !content.includes('NOT Do')) {
|
|
208
|
+
console.log(yellow(' ⚠ ') + `${file} — missing "What does it explicitly NOT do?" section`);
|
|
209
|
+
warnings++;
|
|
210
|
+
continue;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
if (file === 'decisions.md') {
|
|
215
|
+
// Check for at least 2 "## Why" headings
|
|
216
|
+
const decisionCount = (content.match(/^## Why /gm) || []).length;
|
|
217
|
+
if (decisionCount < 2) {
|
|
218
|
+
console.log(yellow(' ⚠ ') + `${file} — only ${decisionCount} decision(s). Most projects have 3+.`);
|
|
219
|
+
warnings++;
|
|
220
|
+
continue;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
if (file === 'entities.md') {
|
|
225
|
+
if (!content.includes('What depends on it')) {
|
|
226
|
+
console.log(yellow(' ⚠ ') + `${file} — entities missing "What depends on it?" field`);
|
|
227
|
+
warnings++;
|
|
228
|
+
continue;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
if (file === 'state.json') {
|
|
233
|
+
try {
|
|
234
|
+
const state = JSON.parse(content);
|
|
235
|
+
if (!state.vibe_updated) {
|
|
236
|
+
console.log(yellow(' ⚠ ') + `${file} — missing vibe_updated timestamp`);
|
|
237
|
+
warnings++;
|
|
238
|
+
continue;
|
|
239
|
+
}
|
|
240
|
+
// Check staleness
|
|
241
|
+
const updated = new Date(state.vibe_updated);
|
|
242
|
+
const daysOld = (Date.now() - updated.getTime()) / (1000 * 60 * 60 * 24);
|
|
243
|
+
if (daysOld > 30) {
|
|
244
|
+
console.log(yellow(' ⚠ ') + `${file} — last updated ${Math.floor(daysOld)} days ago. Consider refreshing.`);
|
|
245
|
+
warnings++;
|
|
246
|
+
continue;
|
|
247
|
+
}
|
|
248
|
+
} catch {
|
|
249
|
+
console.log(red(' ✖ ') + `${file} — invalid JSON`);
|
|
250
|
+
failed++;
|
|
251
|
+
continue;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
if (file === 'flows.md') {
|
|
256
|
+
const flowCount = (content.match(/^## \d+\./gm) || []).length;
|
|
257
|
+
if (flowCount < 2) {
|
|
258
|
+
console.log(yellow(' ⚠ ') + `${file} — only ${flowCount} flow(s). Most projects have 2+.`);
|
|
259
|
+
warnings++;
|
|
260
|
+
continue;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
console.log(green(' ✔ ') + `${file} — ${lines} lines`);
|
|
265
|
+
passed++;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
console.log('');
|
|
269
|
+
if (failed > 0) {
|
|
270
|
+
console.log(red(` Result: ${failed} failed, ${warnings} warnings, ${passed} passed`));
|
|
271
|
+
} else if (warnings > 0) {
|
|
272
|
+
console.log(yellow(` Result: ${warnings} warnings, ${passed} passed`));
|
|
273
|
+
} else {
|
|
274
|
+
console.log(green(` Result: All ${passed} files pass ✔`));
|
|
275
|
+
}
|
|
276
|
+
console.log('');
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
function cmdReset(targetDir) {
|
|
280
|
+
const vibeDir = path.join(targetDir, VIBE_DIR);
|
|
281
|
+
|
|
282
|
+
if (fileExists(vibeDir)) {
|
|
283
|
+
// Remove existing .vibe
|
|
284
|
+
fs.rmSync(vibeDir, { recursive: true, force: true });
|
|
285
|
+
console.log(yellow('\n ⚠ Removed existing .vibe/ folder'));
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
cmdInit(targetDir);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
function printHelp() {
|
|
292
|
+
console.log('');
|
|
293
|
+
console.log(bold(' vibes') + ' — Semantic repository layers for humans and AI');
|
|
294
|
+
console.log('');
|
|
295
|
+
console.log(' ' + bold('Usage:'));
|
|
296
|
+
console.log('');
|
|
297
|
+
console.log(' vibes init Create .vibe/ skeleton in the current directory');
|
|
298
|
+
console.log(' vibes check Validate .vibe/ files for completeness');
|
|
299
|
+
console.log(' vibes reset Delete and recreate .vibe/ skeleton');
|
|
300
|
+
console.log(' vibes help Show this help message');
|
|
301
|
+
console.log('');
|
|
302
|
+
console.log(' ' + bold('What is .vibe?'));
|
|
303
|
+
console.log('');
|
|
304
|
+
console.log(' A small set of 6 files that lets any human or AI understand');
|
|
305
|
+
console.log(' a project without reading the source code.');
|
|
306
|
+
console.log('');
|
|
307
|
+
console.log(' ' + dim('.vibe/'));
|
|
308
|
+
console.log(' ' + dim('├── purpose.md — What is this? Who is it for?'));
|
|
309
|
+
console.log(' ' + dim('├── architecture.md — Systems and how they connect'));
|
|
310
|
+
console.log(' ' + dim('├── flows.md — User journeys, step by step'));
|
|
311
|
+
console.log(' ' + dim('├── entities.md — Important nouns and relationships'));
|
|
312
|
+
console.log(' ' + dim('├── decisions.md — Why things exist the way they do'));
|
|
313
|
+
console.log(' ' + dim('└── state.json — Machine-readable project health'));
|
|
314
|
+
console.log('');
|
|
315
|
+
console.log(' After running ' + cyan('vibes init') + ', point your AI coding agent');
|
|
316
|
+
console.log(' at the project and tell it to read ' + cyan('.vibe/VIBE_GUIDE.md') + '.');
|
|
317
|
+
console.log(' The guide contains everything the agent needs to analyze');
|
|
318
|
+
console.log(' your codebase and fill out the semantic layer.');
|
|
319
|
+
console.log('');
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// ─────────────────────────────────────────────
|
|
323
|
+
// Main
|
|
324
|
+
// ─────────────────────────────────────────────
|
|
325
|
+
|
|
326
|
+
const args = process.argv.slice(2);
|
|
327
|
+
const command = args[0] || 'help';
|
|
328
|
+
const targetDir = path.resolve(args[1] || '.');
|
|
329
|
+
|
|
330
|
+
switch (command) {
|
|
331
|
+
case 'init':
|
|
332
|
+
cmdInit(targetDir);
|
|
333
|
+
break;
|
|
334
|
+
case 'check':
|
|
335
|
+
cmdCheck(targetDir);
|
|
336
|
+
break;
|
|
337
|
+
case 'reset':
|
|
338
|
+
cmdReset(targetDir);
|
|
339
|
+
break;
|
|
340
|
+
case 'help':
|
|
341
|
+
case '--help':
|
|
342
|
+
case '-h':
|
|
343
|
+
printHelp();
|
|
344
|
+
break;
|
|
345
|
+
default:
|
|
346
|
+
console.log(red(`\n Unknown command: ${command}`));
|
|
347
|
+
printHelp();
|
|
348
|
+
process.exit(1);
|
|
349
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "vibe-me",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Create a .vibe/ semantic repository layer for any project. Helps humans and AI agents understand your codebase without reading the source.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"vibes",
|
|
7
|
+
"vibe",
|
|
8
|
+
"documentation",
|
|
9
|
+
"ai",
|
|
10
|
+
"semantic",
|
|
11
|
+
"repository",
|
|
12
|
+
"context",
|
|
13
|
+
"coding-agent",
|
|
14
|
+
"vibe-coding",
|
|
15
|
+
"developer-tools"
|
|
16
|
+
],
|
|
17
|
+
"author": "Joshua M. Abrams",
|
|
18
|
+
"license": "MIT",
|
|
19
|
+
"bin": {
|
|
20
|
+
"vibes": "bin/vibes.js"
|
|
21
|
+
},
|
|
22
|
+
"files": [
|
|
23
|
+
"bin/",
|
|
24
|
+
"templates/",
|
|
25
|
+
"spec/"
|
|
26
|
+
],
|
|
27
|
+
"repository": {
|
|
28
|
+
"type": "git",
|
|
29
|
+
"url": "git+https://github.com/unlimitedinfinit/Vibes.git"
|
|
30
|
+
},
|
|
31
|
+
"engines": {
|
|
32
|
+
"node": ">=16.0.0"
|
|
33
|
+
}
|
|
34
|
+
}
|