vibeman 0.0.9 → 0.0.11
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/dist/api.js +88180 -80376
- package/dist/apps/api/resources/templates/task.md +48 -0
- package/dist/commit.txt +1 -1
- package/dist/index.js +2021 -35
- package/dist/prisma/dev.db +0 -0
- package/dist/prisma/schema.prisma +0 -1
- package/dist/prisma.config.ts +8 -0
- package/dist/scripts/init-test-repo.mjs +234 -0
- package/dist/scripts/lib/test-fixtures.mjs +901 -0
- package/dist/scripts/seed-test-fixtures.mjs +281 -0
- package/dist/ui/assets/{index-BbfDsh-D.js → index-5kvaa7VH.js} +1 -1
- package/dist/ui/assets/{index-Bb69tSxN.js → index-B2YlQpV0.js} +1 -1
- package/dist/ui/assets/{index-C-OxxnxE.js → index-BFpKdhc4.js} +1 -1
- package/dist/ui/assets/{index-qDf_Uo6N.js → index-BKcn2ir8.js} +1 -1
- package/dist/ui/assets/{index-CW8VfVIC.js → index-BmCH7Zkp.js} +88 -94
- package/dist/ui/assets/{index-EHnTtRu0.js → index-BnA5v3sz.js} +1 -1
- package/dist/ui/assets/{index-DqEtuI-j.js → index-BtgmEMNX.js} +1 -1
- package/dist/ui/assets/{index-B7PC3UwW.js → index-Buod5MG9.js} +1 -1
- package/dist/ui/assets/{index-Dhrbisdh.js → index-BxFJT2l4.js} +1 -1
- package/dist/ui/assets/{index-BEEMkSga.js → index-CCzed9cx.js} +1 -1
- package/dist/ui/assets/{index-SowqJRTb.js → index-CJ0FVxY4.js} +1 -1
- package/dist/ui/assets/{index-ZYq2otFn.js → index-CaM8gf-6.js} +1 -1
- package/dist/ui/assets/{index-DQTqMEWL.js → index-CfiNAuWd.js} +1 -1
- package/dist/ui/assets/{index-Cb3j0p9y.js → index-Ck0eDlqj.js} +1 -1
- package/dist/ui/assets/{index-F3UrAKk1.js → index-CmzQ8vUy.js} +1 -1
- package/dist/ui/assets/{index-Du9IbowE.js → index-CoX8THvk.js} +1 -1
- package/dist/ui/assets/{index-BZ4ywKS-.js → index-D4lRQ9OU.js} +1 -1
- package/dist/ui/assets/{index-Bu9gi8CT.js → index-DCwTMEKA.js} +1 -1
- package/dist/ui/assets/{index-hJzy_UWf.js → index-D_p2Z3lg.js} +1 -1
- package/dist/ui/assets/{index-DrA24vfU.js → index-DlPVzvxz.js} +1 -1
- package/dist/ui/assets/{index-CwR-eksU.js → index-Q46jjFaN.js} +1 -1
- package/dist/ui/assets/{index-CH876Txt.js → index-XVbgp8h-.js} +1 -1
- package/dist/ui/assets/{index-iMeltPfH.js → index-xr3-NPcF.js} +1 -1
- package/dist/ui/index.html +1 -1
- package/package.json +10 -3
|
Binary file
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { spawn } from 'node:child_process';
|
|
3
|
+
import { existsSync } from 'node:fs';
|
|
4
|
+
import { mkdir, readdir, readFile, writeFile } from 'node:fs/promises';
|
|
5
|
+
import { basename, resolve } from 'node:path';
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
PRIMARY_TEST_TASK_ID,
|
|
9
|
+
PRIMARY_TEST_WORKFLOW_ID,
|
|
10
|
+
TEST_FIXTURE_TASKS,
|
|
11
|
+
TEST_FIXTURE_WORKFLOWS,
|
|
12
|
+
buildTaskMarkdown,
|
|
13
|
+
getRepoRoot,
|
|
14
|
+
readTaskTemplate,
|
|
15
|
+
taskFilename,
|
|
16
|
+
taskRelativePath,
|
|
17
|
+
} from './lib/test-fixtures.mjs';
|
|
18
|
+
|
|
19
|
+
function parseArgs(argv) {
|
|
20
|
+
const args = {
|
|
21
|
+
path: '',
|
|
22
|
+
force: false,
|
|
23
|
+
skipDbSeed: false,
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
27
|
+
const arg = argv[i];
|
|
28
|
+
|
|
29
|
+
if (arg === '--path') {
|
|
30
|
+
args.path = argv[i + 1] ?? '';
|
|
31
|
+
i += 1;
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (arg === '--force') {
|
|
36
|
+
args.force = true;
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (arg === '--skip-db-seed') {
|
|
41
|
+
args.skipDbSeed = true;
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (!arg.startsWith('-') && !args.path) {
|
|
46
|
+
args.path = arg;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return args;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function runCommand(cmd, cmdArgs, options = {}) {
|
|
54
|
+
return new Promise((resolvePromise, rejectPromise) => {
|
|
55
|
+
const child = spawn(cmd, cmdArgs, {
|
|
56
|
+
stdio: options.stdio ?? 'inherit',
|
|
57
|
+
cwd: options.cwd,
|
|
58
|
+
env: options.env,
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
let stdout = '';
|
|
62
|
+
let stderr = '';
|
|
63
|
+
|
|
64
|
+
if (child.stdout) {
|
|
65
|
+
child.stdout.on('data', (chunk) => {
|
|
66
|
+
stdout += chunk.toString();
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
if (child.stderr) {
|
|
70
|
+
child.stderr.on('data', (chunk) => {
|
|
71
|
+
stderr += chunk.toString();
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
child.on('error', (error) => {
|
|
76
|
+
rejectPromise(error);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
child.on('exit', (code) => {
|
|
80
|
+
if (code === 0) {
|
|
81
|
+
resolvePromise({ stdout, stderr });
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
rejectPromise(
|
|
85
|
+
new Error(
|
|
86
|
+
`Command failed (${code ?? 'null'}): ${cmd} ${cmdArgs.join(' ')}\n${stderr || stdout}`,
|
|
87
|
+
),
|
|
88
|
+
);
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
async function ensureDirectoryIsEmpty(targetRoot, force) {
|
|
94
|
+
await mkdir(targetRoot, { recursive: true });
|
|
95
|
+
const entries = await readdir(targetRoot, { withFileTypes: true });
|
|
96
|
+
const allowedNames = new Set(['.git', '.DS_Store']);
|
|
97
|
+
const blocked = entries.filter((entry) => !allowedNames.has(entry.name));
|
|
98
|
+
|
|
99
|
+
if (blocked.length > 0 && !force) {
|
|
100
|
+
const names = blocked.map((entry) => entry.name).join(', ');
|
|
101
|
+
throw new Error(
|
|
102
|
+
`Target directory is not empty: ${targetRoot}\nFound: ${names}\nUse --force to continue.`,
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
async function writeTaskTemplate(targetRoot) {
|
|
108
|
+
const templatePath = resolve(targetRoot, '.vibeman/templates/task.md');
|
|
109
|
+
await mkdir(resolve(targetRoot, '.vibeman/templates'), { recursive: true });
|
|
110
|
+
await writeFile(templatePath, readTaskTemplate(), 'utf8');
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
async function writeFixtureTaskFiles(targetRoot) {
|
|
114
|
+
const tasksDir = resolve(targetRoot, '.vibeman/tasks');
|
|
115
|
+
await mkdir(tasksDir, { recursive: true });
|
|
116
|
+
|
|
117
|
+
const nowIso = new Date().toISOString();
|
|
118
|
+
|
|
119
|
+
for (const taskDef of TEST_FIXTURE_TASKS) {
|
|
120
|
+
const taskPath = resolve(tasksDir, taskFilename(taskDef.id));
|
|
121
|
+
await writeFile(taskPath, buildTaskMarkdown(taskDef, nowIso), 'utf8');
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
async function upsertGitignore(targetRoot) {
|
|
126
|
+
const gitignorePath = resolve(targetRoot, '.gitignore');
|
|
127
|
+
const requiredLines = ['.vibeman/vibeman.db', '.vibeman/uploads'];
|
|
128
|
+
|
|
129
|
+
let existing = '';
|
|
130
|
+
if (existsSync(gitignorePath)) {
|
|
131
|
+
existing = await readFile(gitignorePath, 'utf8');
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const lines = existing
|
|
135
|
+
.split(/\r?\n/)
|
|
136
|
+
.map((line) => line.trim())
|
|
137
|
+
.filter(Boolean);
|
|
138
|
+
const current = new Set(lines);
|
|
139
|
+
let changed = false;
|
|
140
|
+
|
|
141
|
+
for (const line of requiredLines) {
|
|
142
|
+
if (!current.has(line)) {
|
|
143
|
+
lines.push(line);
|
|
144
|
+
changed = true;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
if (!existsSync(gitignorePath) || changed) {
|
|
149
|
+
const next = `${lines.join('\n')}\n`;
|
|
150
|
+
await writeFile(gitignorePath, next, 'utf8');
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
async function ensureGitRepo(targetRoot) {
|
|
155
|
+
const hasGitDir = existsSync(resolve(targetRoot, '.git'));
|
|
156
|
+
if (!hasGitDir) {
|
|
157
|
+
await runCommand('git', ['init'], { cwd: targetRoot });
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
await runCommand('git', ['add', '.'], { cwd: targetRoot });
|
|
161
|
+
|
|
162
|
+
let hasHead = true;
|
|
163
|
+
try {
|
|
164
|
+
await runCommand('git', ['rev-parse', '--verify', 'HEAD'], {
|
|
165
|
+
cwd: targetRoot,
|
|
166
|
+
stdio: 'pipe',
|
|
167
|
+
});
|
|
168
|
+
} catch {
|
|
169
|
+
hasHead = false;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if (hasHead) {
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
try {
|
|
177
|
+
await runCommand('git', ['config', 'user.email'], { cwd: targetRoot, stdio: 'pipe' });
|
|
178
|
+
} catch {
|
|
179
|
+
await runCommand('git', ['config', 'user.email', 'vibeman-fixture@example.com'], {
|
|
180
|
+
cwd: targetRoot,
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
try {
|
|
185
|
+
await runCommand('git', ['config', 'user.name'], { cwd: targetRoot, stdio: 'pipe' });
|
|
186
|
+
} catch {
|
|
187
|
+
await runCommand('git', ['config', 'user.name', 'Vibeman Fixture'], { cwd: targetRoot });
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
await runCommand('git', ['commit', '-m', 'chore: initialize vibeman test fixtures'], {
|
|
191
|
+
cwd: targetRoot,
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
async function seedFixtures(targetRoot) {
|
|
196
|
+
const repoRoot = getRepoRoot();
|
|
197
|
+
const scriptPath = resolve(repoRoot, 'scripts/seed-test-fixtures.mjs');
|
|
198
|
+
|
|
199
|
+
await runCommand('node', [scriptPath, '--root', targetRoot], {
|
|
200
|
+
cwd: repoRoot,
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
async function main() {
|
|
205
|
+
const args = parseArgs(process.argv.slice(2));
|
|
206
|
+
const targetRoot = resolve(process.cwd(), args.path || '.');
|
|
207
|
+
|
|
208
|
+
await ensureDirectoryIsEmpty(targetRoot, args.force);
|
|
209
|
+
await writeTaskTemplate(targetRoot);
|
|
210
|
+
await writeFixtureTaskFiles(targetRoot);
|
|
211
|
+
await upsertGitignore(targetRoot);
|
|
212
|
+
await ensureGitRepo(targetRoot);
|
|
213
|
+
|
|
214
|
+
if (!args.skipDbSeed) {
|
|
215
|
+
await seedFixtures(targetRoot);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
console.log('[fixture:init] done');
|
|
219
|
+
console.log(` repo: ${targetRoot}`);
|
|
220
|
+
console.log(` tasks: ${TEST_FIXTURE_TASKS.length}`);
|
|
221
|
+
console.log(` workflows: ${TEST_FIXTURE_WORKFLOWS.length}`);
|
|
222
|
+
console.log(` sample task: ${taskRelativePath(PRIMARY_TEST_TASK_ID)}`);
|
|
223
|
+
console.log(` sample workflow: ${PRIMARY_TEST_WORKFLOW_ID}`);
|
|
224
|
+
console.log('');
|
|
225
|
+
console.log('Repository fixtures initialized. Start your app manually and run tests as needed.');
|
|
226
|
+
console.log(`Tip: vibeman start ${targetRoot}`);
|
|
227
|
+
console.log(`Open project root: ${basename(targetRoot)}`);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
main().catch((error) => {
|
|
231
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
232
|
+
console.error(`[fixture:init] failed: ${message}`);
|
|
233
|
+
process.exit(1);
|
|
234
|
+
});
|