buildcrew 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/bin/setup.js ADDED
@@ -0,0 +1,429 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { readdir, copyFile, mkdir, readFile, writeFile, access } from "fs/promises";
4
+ import { join, dirname } from "path";
5
+ import { fileURLToPath } from "url";
6
+ import { createInterface } from "readline";
7
+
8
+ const __dirname = dirname(fileURLToPath(import.meta.url));
9
+ const AGENTS_SRC = join(__dirname, "..", "agents");
10
+ const TEMPLATES_SRC = join(__dirname, "..", "templates");
11
+ const TARGET_DIR = join(process.cwd(), ".claude", "agents");
12
+ const HARNESS_DIR = join(process.cwd(), ".claude", "harness");
13
+ const VERSION = "1.0.0";
14
+
15
+ const RESET = "\x1b[0m";
16
+ const BOLD = "\x1b[1m";
17
+ const DIM = "\x1b[2m";
18
+ const GREEN = "\x1b[32m";
19
+ const YELLOW = "\x1b[33m";
20
+ const CYAN = "\x1b[36m";
21
+ const MAGENTA = "\x1b[35m";
22
+ const RED = "\x1b[31m";
23
+
24
+ function log(msg) { console.log(msg); }
25
+
26
+ async function exists(path) {
27
+ try { await access(path); return true; } catch { return false; }
28
+ }
29
+
30
+ // ─── Template registry ───
31
+
32
+ const TEMPLATES = {
33
+ "project": { file: null, desc: "Project context (auto-generated by init)", category: "core" },
34
+ "rules": { file: null, desc: "Team rules & conventions (auto-generated by init)", category: "core" },
35
+ "erd": { file: "erd.md", desc: "Database schema & entity relationships", category: "data" },
36
+ "architecture": { file: "architecture.md", desc: "System architecture & tech stack overview", category: "system" },
37
+ "api-spec": { file: "api-spec.md", desc: "API endpoints & contracts", category: "system" },
38
+ "design-system": { file: "design-system.md", desc: "Colors, typography, spacing, components", category: "design" },
39
+ "glossary": { file: "glossary.md", desc: "Domain terms, user roles, status flows", category: "domain" },
40
+ "user-flow": { file: "user-flow.md", desc: "User journeys, page map, error paths", category: "domain" },
41
+ "env-vars": { file: "env-vars.md", desc: "Environment variables & secrets guide", category: "system" },
42
+ };
43
+
44
+ // ─── Interactive prompt ───
45
+
46
+ function createPrompt() {
47
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
48
+ const ask = (q) => new Promise(resolve => rl.question(q, resolve));
49
+ const close = () => rl.close();
50
+ return { ask, close };
51
+ }
52
+
53
+ // ─── Auto-detect project info ───
54
+
55
+ async function detectProject() {
56
+ const info = { name: "", stack: [], framework: "", hasTS: false, hasTailwind: false, hasI18n: false, hasAuth: false, hasDB: false };
57
+ try {
58
+ const pkg = JSON.parse(await readFile(join(process.cwd(), "package.json"), "utf8"));
59
+ info.name = pkg.name || "";
60
+ const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
61
+ if (allDeps["next"]) { info.framework = "Next.js"; info.stack.push("Next.js"); }
62
+ else if (allDeps["nuxt"]) { info.framework = "Nuxt"; info.stack.push("Nuxt"); }
63
+ else if (allDeps["react"]) { info.framework = "React"; info.stack.push("React"); }
64
+ else if (allDeps["vue"]) { info.framework = "Vue"; info.stack.push("Vue"); }
65
+ else if (allDeps["svelte"] || allDeps["@sveltejs/kit"]) { info.framework = "SvelteKit"; info.stack.push("SvelteKit"); }
66
+ else if (allDeps["express"]) { info.framework = "Express"; info.stack.push("Express"); }
67
+ if (allDeps["typescript"]) { info.hasTS = true; info.stack.push("TypeScript"); }
68
+ if (allDeps["tailwindcss"]) { info.hasTailwind = true; info.stack.push("TailwindCSS"); }
69
+ if (allDeps["next-intl"] || allDeps["i18next"] || allDeps["react-intl"]) { info.hasI18n = true; info.stack.push("i18n"); }
70
+ if (allDeps["@supabase/supabase-js"]) { info.hasDB = true; info.stack.push("Supabase"); }
71
+ else if (allDeps["prisma"] || allDeps["@prisma/client"]) { info.hasDB = true; info.stack.push("Prisma"); }
72
+ else if (allDeps["drizzle-orm"]) { info.hasDB = true; info.stack.push("Drizzle"); }
73
+ if (allDeps["next-auth"] || allDeps["@auth/core"] || allDeps["@supabase/auth-helpers-nextjs"]) { info.hasAuth = true; info.stack.push("Auth"); }
74
+ if (allDeps["stripe"] || allDeps["@paddle/paddle-js"]) { info.stack.push("Payments"); }
75
+ } catch {}
76
+ return info;
77
+ }
78
+
79
+ // ─── Add: copy template to harness ───
80
+
81
+ async function runAdd(type, force) {
82
+ if (!type) {
83
+ log(`\n ${BOLD}Available harness templates:${RESET}\n`);
84
+ const categories = { core: "Core (auto-created by init)", data: "Data", system: "System", design: "Design", domain: "Domain" };
85
+ for (const [cat, label] of Object.entries(categories)) {
86
+ const items = Object.entries(TEMPLATES).filter(([, v]) => v.category === cat);
87
+ if (items.length === 0) continue;
88
+ log(` ${CYAN}${label}${RESET}`);
89
+ for (const [name, info] of items) {
90
+ const installed = await exists(join(HARNESS_DIR, `${name}.md`));
91
+ const status = installed ? `${GREEN}installed${RESET}` : `${DIM}not installed${RESET}`;
92
+ log(` ${BOLD}${name.padEnd(16)}${RESET} ${status} ${DIM}${info.desc}${RESET}`);
93
+ }
94
+ log("");
95
+ }
96
+ log(` ${BOLD}Usage:${RESET} npx buildcrew add ${CYAN}<template>${RESET}`);
97
+ log(` ${BOLD}Example:${RESET} npx buildcrew add erd\n`);
98
+ return;
99
+ }
100
+
101
+ const template = TEMPLATES[type];
102
+ if (!template) {
103
+ log(`\n ${RED}Unknown template: ${type}${RESET}`);
104
+ log(` ${DIM}Run ${BOLD}npx buildcrew add${RESET}${DIM} to see available templates.${RESET}\n`);
105
+ return;
106
+ }
107
+
108
+ if (!template.file) {
109
+ log(`\n ${YELLOW}${type}.md is auto-generated by ${BOLD}npx buildcrew init${RESET}`);
110
+ log(` ${DIM}Run init to create it, or create .claude/harness/${type}.md manually.${RESET}\n`);
111
+ return;
112
+ }
113
+
114
+ const target = join(HARNESS_DIR, `${type}.md`);
115
+ if ((await exists(target)) && !force) {
116
+ log(`\n ${YELLOW}${type}.md already exists.${RESET} Use ${BOLD}--force${RESET} to overwrite.\n`);
117
+ return;
118
+ }
119
+
120
+ await mkdir(HARNESS_DIR, { recursive: true });
121
+ await copyFile(join(TEMPLATES_SRC, template.file), target);
122
+ log(`\n ${GREEN} + ${RESET} .claude/harness/${type}.md`);
123
+ log(` ${DIM}Edit this file to fill in your project details.${RESET}`);
124
+ log(` ${DIM}All agents will read it automatically.${RESET}\n`);
125
+ }
126
+
127
+ // ─── Init: Harness Engineering ───
128
+
129
+ async function runInit(force) {
130
+ log(`\n ${BOLD}buildcrew init${RESET} — Harness Engineering Setup\n`);
131
+ log(` ${DIM}Setting up project context and team rules.${RESET}`);
132
+ log(` ${DIM}All 11 agents will read these before every task.${RESET}\n`);
133
+
134
+ if ((await exists(join(HARNESS_DIR, "project.md"))) && !force) {
135
+ log(` ${YELLOW}Harness already exists at .claude/harness/${RESET}`);
136
+ log(` ${DIM}Use ${BOLD}npx buildcrew init --force${RESET}${DIM} to overwrite.${RESET}\n`);
137
+ return;
138
+ }
139
+
140
+ const detected = await detectProject();
141
+ const { ask, close } = createPrompt();
142
+
143
+ try {
144
+ log(` ${CYAN}${BOLD}[1/3] Project Context${RESET}\n`);
145
+ const name = (await ask(` ${BOLD}Project name${RESET} ${DIM}(${detected.name || "none"})${RESET}: `)) || detected.name || "my-project";
146
+ const description = await ask(` ${BOLD}What does this project do?${RESET} (1 sentence): `);
147
+ const stackAuto = detected.stack.length > 0 ? detected.stack.join(", ") : "not detected";
148
+ const stackExtra = await ask(` ${BOLD}Tech stack${RESET} ${DIM}(detected: ${stackAuto})${RESET}\n ${DIM}Add anything missing (comma-separated, or Enter):${RESET} `);
149
+ const deployTarget = await ask(` ${BOLD}Deploy target${RESET} ${DIM}(Vercel, AWS, etc.)${RESET}: `);
150
+ const prodUrl = await ask(` ${BOLD}Production URL${RESET} ${DIM}(or Enter to skip)${RESET}: `);
151
+
152
+ log(`\n ${CYAN}${BOLD}[2/3] Team Rules${RESET}\n`);
153
+ const conventions = await ask(` ${BOLD}Coding conventions${RESET}\n ${DIM}(e.g., "functional components only, no default exports")${RESET}\n : `);
154
+ const priorities = await ask(` ${BOLD}What to prioritize${RESET}\n ${DIM}(e.g., "UX over performance, security first")${RESET}\n : `);
155
+ const avoid = await ask(` ${BOLD}What to avoid${RESET}\n ${DIM}(e.g., "no class components, no any types")${RESET}\n : `);
156
+ const quality = await ask(` ${BOLD}Quality standards${RESET}\n ${DIM}(e.g., "all code must pass tsc, no console.log")${RESET}\n : `);
157
+ const reviewRules = await ask(` ${BOLD}Review rules${RESET}\n ${DIM}(e.g., "always check auth on API routes, mobile-first")${RESET}\n : `);
158
+
159
+ log(`\n ${CYAN}${BOLD}[3/3] Domain Knowledge${RESET}\n`);
160
+ const domain = await ask(` ${BOLD}Domain${RESET} ${DIM}(e.g., "e-commerce", "fintech")${RESET}: `);
161
+ const userTypes = await ask(` ${BOLD}User types${RESET} ${DIM}(e.g., "free, premium, admin")${RESET}: `);
162
+ const keyTerms = await ask(` ${BOLD}Key terms${RESET}\n ${DIM}(e.g., "reading=tarot session, spread=card layout")${RESET}\n : `);
163
+ const businessRules = await ask(` ${BOLD}Business rules${RESET}\n ${DIM}(e.g., "free=3 reads/day, premium=unlimited")${RESET}\n : `);
164
+
165
+ close();
166
+
167
+ await mkdir(HARNESS_DIR, { recursive: true });
168
+ const fullStack = [...detected.stack, ...(stackExtra ? stackExtra.split(",").map(s => s.trim()) : [])].filter(Boolean);
169
+
170
+ const projectMd = `# Project: ${name}
171
+
172
+ ## Overview
173
+ ${description || "[Edit: describe your project]"}
174
+
175
+ ## Tech Stack
176
+ ${fullStack.map(s => `- ${s}`).join("\n") || "- [Edit: add your tech stack]"}
177
+
178
+ ## Framework
179
+ ${detected.framework || "[Not detected]"}
180
+
181
+ ## Infrastructure
182
+ - **Deploy**: ${deployTarget || "[Edit]"}
183
+ - **Production URL**: ${prodUrl || "[Edit]"}
184
+ - **TypeScript**: ${detected.hasTS ? "Yes" : "No"}
185
+ - **CSS**: ${detected.hasTailwind ? "TailwindCSS" : "[Edit]"}
186
+ - **i18n**: ${detected.hasI18n ? "Yes" : "No"}
187
+ - **Auth**: ${detected.hasAuth ? "Yes" : "No"}
188
+ - **Database**: ${detected.hasDB ? "Yes" : "No"}
189
+
190
+ ## Domain
191
+ - **Industry**: ${domain || "[Edit]"}
192
+ - **User types**: ${userTypes || "[Edit]"}
193
+
194
+ ## Key Domain Terms
195
+ ${keyTerms ? keyTerms.split(",").map(t => `- ${t.trim()}`).join("\n") : "- [Edit: add domain-specific terms]"}
196
+
197
+ ## Business Rules
198
+ ${businessRules ? businessRules.split(",").map(r => `- ${r.trim()}`).join("\n") : "- [Edit: add business rules]"}
199
+ `;
200
+
201
+ const rulesMd = `# Team Rules
202
+
203
+ These rules apply to ALL agents. Every agent reads this before starting work.
204
+
205
+ ## Coding Conventions
206
+ ${conventions ? conventions.split(",").map(c => `- ${c.trim()}`).join("\n") : "- Follow existing codebase patterns"}
207
+
208
+ ## Priorities
209
+ ${priorities ? priorities.split(",").map(p => `- ${p.trim()}`).join("\n") : "- [Edit: set your priorities]"}
210
+
211
+ ## What to Avoid
212
+ ${avoid ? avoid.split(",").map(a => `- ${a.trim()}`).join("\n") : "- [Edit: list things to avoid]"}
213
+
214
+ ## Quality Standards
215
+ ${quality ? quality.split(",").map(q => `- ${q.trim()}`).join("\n") : "- All code must pass type checker and linter\n- No debug logs in production"}
216
+
217
+ ## Review Standards
218
+ ${reviewRules ? reviewRules.split(",").map(r => `- ${r.trim()}`).join("\n") : "- [Edit: add review rules]"}
219
+ `;
220
+
221
+ await writeFile(join(HARNESS_DIR, "project.md"), projectMd);
222
+ await writeFile(join(HARNESS_DIR, "rules.md"), rulesMd);
223
+
224
+ log(`\n ${GREEN}${BOLD}Harness created!${RESET}\n`);
225
+ log(` ${GREEN} + ${RESET} .claude/harness/project.md`);
226
+ log(` ${GREEN} + ${RESET} .claude/harness/rules.md`);
227
+
228
+ // Suggest additional templates
229
+ log(`\n ${BOLD}Add more context with templates:${RESET}\n`);
230
+ const suggestions = [
231
+ ["erd", "Database schema & relationships"],
232
+ ["architecture", "System architecture overview"],
233
+ ["api-spec", "API endpoints & contracts"],
234
+ ["design-system", "Colors, typography, components"],
235
+ ["glossary", "Domain terms & user roles"],
236
+ ["user-flow", "User journeys & page map"],
237
+ ["env-vars", "Environment variables guide"],
238
+ ];
239
+ for (const [name, desc] of suggestions) {
240
+ log(` ${DIM}npx buildcrew add ${CYAN}${name.padEnd(15)}${RESET} ${DIM}${desc}${RESET}`);
241
+ }
242
+
243
+ log(`\n ${DIM}Or create any .md file in .claude/harness/ — agents read them all.${RESET}\n`);
244
+
245
+ if (!(await exists(TARGET_DIR))) {
246
+ log(` ${YELLOW}Agents not installed yet.${RESET} Run ${BOLD}npx buildcrew${RESET} first.\n`);
247
+ }
248
+
249
+ } catch (err) {
250
+ close();
251
+ throw err;
252
+ }
253
+ }
254
+
255
+ // ─── Harness status ───
256
+
257
+ async function runHarnessStatus() {
258
+ log(`\n ${BOLD}Harness files${RESET} ${DIM}(.claude/harness/)${RESET}\n`);
259
+
260
+ if (!(await exists(HARNESS_DIR))) {
261
+ log(` ${YELLOW}No harness directory found.${RESET}`);
262
+ log(` ${DIM}Run ${BOLD}npx buildcrew init${RESET}${DIM} to get started.${RESET}\n`);
263
+ return;
264
+ }
265
+
266
+ const files = (await readdir(HARNESS_DIR)).filter(f => f.endsWith(".md")).sort();
267
+ if (files.length === 0) {
268
+ log(` ${YELLOW}Harness directory is empty.${RESET}\n`);
269
+ return;
270
+ }
271
+
272
+ for (const file of files) {
273
+ const name = file.replace(".md", "");
274
+ const isTemplate = TEMPLATES[name];
275
+ const content = await readFile(join(HARNESS_DIR, file), "utf8");
276
+ const lines = content.split("\n").length;
277
+ const hasEdits = !content.includes("[Edit");
278
+ const status = hasEdits ? `${GREEN}configured${RESET}` : `${YELLOW}needs editing${RESET}`;
279
+ const desc = isTemplate ? `${DIM}${isTemplate.desc}${RESET}` : `${DIM}(custom)${RESET}`;
280
+ log(` ${BOLD}${name.padEnd(16)}${RESET} ${status} ${lines} lines ${desc}`);
281
+ }
282
+
283
+ log(`\n ${DIM}Agents read ALL .md files here. Add any file you want.${RESET}\n`);
284
+ }
285
+
286
+ // ─── Install agents ───
287
+
288
+ async function runInstall(force) {
289
+ const files = (await readdir(AGENTS_SRC)).filter(f => f.endsWith(".md"));
290
+ log(`\n ${BOLD}buildcrew${RESET} v${VERSION}\n ${DIM}11 AI agents for Claude Code${RESET}\n`);
291
+ log(`${DIM} Installing to ${TARGET_DIR}${RESET}\n`);
292
+
293
+ await mkdir(TARGET_DIR, { recursive: true });
294
+ let installed = 0, skipped = 0;
295
+
296
+ for (const file of files) {
297
+ const target = join(TARGET_DIR, file);
298
+ if ((await exists(target)) && !force) {
299
+ log(` ${YELLOW}skip${RESET} ${file} ${DIM}(exists, use --force)${RESET}`);
300
+ skipped++;
301
+ continue;
302
+ }
303
+ await copyFile(join(AGENTS_SRC, file), target);
304
+ log(` ${GREEN} + ${RESET} ${file}`);
305
+ installed++;
306
+ }
307
+
308
+ log("");
309
+ if (installed > 0) {
310
+ log(` ${GREEN}${BOLD}Done!${RESET} ${installed} agents installed.${skipped > 0 ? ` ${skipped} skipped.` : ""}\n`);
311
+ } else {
312
+ log(` ${YELLOW}All agents already exist.${RESET} Use ${BOLD}--force${RESET} to overwrite.\n`);
313
+ }
314
+
315
+ const hasHarness = await exists(join(HARNESS_DIR, "project.md"));
316
+ if (!hasHarness) {
317
+ log(` ${CYAN}Next:${RESET} Run ${BOLD}npx buildcrew init${RESET} to set up your project harness.\n`);
318
+ }
319
+
320
+ let hasPlaywright = false;
321
+ try {
322
+ const settingsPath = join(process.env.HOME, ".claude", "settings.json");
323
+ if (await exists(settingsPath)) {
324
+ hasPlaywright = (await readFile(settingsPath, "utf8")).includes("playwright");
325
+ }
326
+ } catch {}
327
+ if (!hasPlaywright) {
328
+ log(` ${YELLOW}Optional:${RESET} Playwright MCP not detected.`);
329
+ log(` ${DIM}Setup: claude mcp add playwright -- npx @anthropic-ai/mcp-server-playwright${RESET}\n`);
330
+ }
331
+
332
+ log(` ${BOLD}Quick start:${RESET} @constitution [your request]\n`);
333
+ }
334
+
335
+ // ─── List agents ───
336
+
337
+ async function runList() {
338
+ const files = (await readdir(AGENTS_SRC)).filter(f => f.endsWith(".md"));
339
+ log(`\n ${BOLD}buildcrew${RESET} v${VERSION} — 11 agents\n`);
340
+ for (const file of files) {
341
+ const content = await readFile(join(AGENTS_SRC, file), "utf8");
342
+ const nameMatch = content.match(/^name:\s*(.+)$/m);
343
+ const descMatch = content.match(/^description:\s*(.+)$/m);
344
+ const modelMatch = content.match(/^model:\s*(.+)$/m);
345
+ const name = nameMatch ? nameMatch[1] : file.replace(".md", "");
346
+ const desc = descMatch ? descMatch[1] : "";
347
+ const model = modelMatch ? modelMatch[1] : "sonnet";
348
+ const modelTag = model === "opus" ? `${MAGENTA}opus${RESET}` : `${DIM}sonnet${RESET}`;
349
+ const color = name === "constitution" ? BOLD : "";
350
+ log(` ${color}${name.padEnd(20)}${RESET} ${modelTag} ${DIM}${desc.slice(0, 55)}${RESET}`);
351
+ }
352
+ log("");
353
+ }
354
+
355
+ // ─── Uninstall ───
356
+
357
+ async function runUninstall() {
358
+ const files = (await readdir(AGENTS_SRC)).filter(f => f.endsWith(".md"));
359
+ if (!(await exists(TARGET_DIR))) {
360
+ log(`${YELLOW}No .claude/agents/ directory found.${RESET}`);
361
+ return;
362
+ }
363
+ let removed = 0;
364
+ for (const file of files) {
365
+ const target = join(TARGET_DIR, file);
366
+ if (await exists(target)) { const { unlink } = await import("fs/promises"); await unlink(target); removed++; }
367
+ }
368
+ log(`${GREEN}Removed ${removed} agent files.${RESET}`);
369
+ }
370
+
371
+ // ─── Main ───
372
+
373
+ async function main() {
374
+ const args = process.argv.slice(2);
375
+ const command = args[0];
376
+ const subcommand = args[1];
377
+ const force = args.includes("--force") || args.includes("-f");
378
+
379
+ if (args.includes("--version") || args.includes("-v")) {
380
+ log(`buildcrew v${VERSION}`);
381
+ return;
382
+ }
383
+
384
+ if (args.includes("--help") || args.includes("-h")) {
385
+ log(`
386
+ ${BOLD}buildcrew${RESET} v${VERSION} — 11 AI agents for Claude Code
387
+
388
+ ${BOLD}Commands:${RESET}
389
+ npx buildcrew Install agents
390
+ npx buildcrew init Set up project harness (interactive)
391
+ npx buildcrew add List available harness templates
392
+ npx buildcrew add <template> Add a harness template
393
+ npx buildcrew harness Show harness status
394
+
395
+ ${BOLD}Options:${RESET}
396
+ --force, -f Overwrite existing files
397
+ --list, -l List all agents
398
+ --uninstall Remove installed agents
399
+ --version, -v Show version
400
+
401
+ ${BOLD}Setup (recommended):${RESET}
402
+ ${GREEN}1.${RESET} npx buildcrew ${DIM}Install agent files${RESET}
403
+ ${GREEN}2.${RESET} npx buildcrew init ${DIM}Project context + team rules${RESET}
404
+ ${GREEN}3.${RESET} npx buildcrew add erd ${DIM}Add more context (optional)${RESET}
405
+ ${GREEN}4.${RESET} @constitution [task] ${DIM}Start working${RESET}
406
+
407
+ ${BOLD}Harness templates:${RESET}
408
+ erd, architecture, api-spec, design-system,
409
+ glossary, user-flow, env-vars
410
+ ${DIM}Or create any .md file in .claude/harness/${RESET}
411
+
412
+ ${BOLD}More info:${RESET} https://github.com/z1nun/buildcrew
413
+ `);
414
+ return;
415
+ }
416
+
417
+ if (args.includes("--list") || args.includes("-l")) return runList();
418
+ if (args.includes("--uninstall")) return runUninstall();
419
+ if (command === "init") return runInit(force);
420
+ if (command === "add") return runAdd(subcommand, force);
421
+ if (command === "harness") return runHarnessStatus();
422
+
423
+ return runInstall(force);
424
+ }
425
+
426
+ main().catch(err => {
427
+ console.error(`${RED}Error:${RESET} ${err.message}`);
428
+ process.exit(1);
429
+ });
package/package.json ADDED
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "buildcrew",
3
+ "version": "1.0.0",
4
+ "description": "11 AI agents for Claude Code — auto-orchestrated dev team with 9 operating modes",
5
+ "author": "z1nun",
6
+ "license": "MIT",
7
+ "type": "module",
8
+ "bin": {
9
+ "buildcrew": "./bin/setup.js"
10
+ },
11
+ "files": [
12
+ "bin/",
13
+ "agents/",
14
+ "README.md",
15
+ "LICENSE"
16
+ ],
17
+ "keywords": [
18
+ "claude",
19
+ "claude-code",
20
+ "ai-agents",
21
+ "ai-team",
22
+ "code-review",
23
+ "qa-testing",
24
+ "security-audit",
25
+ "playwright",
26
+ "developer-tools",
27
+ "vibecoding",
28
+ "buildcrew"
29
+ ],
30
+ "repository": {
31
+ "type": "git",
32
+ "url": "https://github.com/z1nun/buildcrew.git"
33
+ },
34
+ "engines": {
35
+ "node": ">=18"
36
+ }
37
+ }