buildwright 0.0.3
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/README.md +82 -0
- package/bin/buildwright.js +39 -0
- package/package.json +24 -0
- package/src/commands/init.js +88 -0
- package/src/commands/sync.js +33 -0
- package/src/commands/update.js +135 -0
- package/src/utils/copy-files.js +61 -0
- package/src/utils/detect.js +27 -0
- package/src/utils/run-script.js +65 -0
- package/templates/.buildwright/agents/README.md +53 -0
- package/templates/.buildwright/agents/architect.md +143 -0
- package/templates/.buildwright/agents/security-engineer.md +193 -0
- package/templates/.buildwright/agents/staff-engineer.md +134 -0
- package/templates/.buildwright/claws/README.md +89 -0
- package/templates/.buildwright/claws/TEMPLATE.md +71 -0
- package/templates/.buildwright/claws/backend.md +114 -0
- package/templates/.buildwright/claws/database.md +120 -0
- package/templates/.buildwright/claws/devops.md +175 -0
- package/templates/.buildwright/claws/frontend.md +111 -0
- package/templates/.buildwright/commands/bw-analyse.md +82 -0
- package/templates/.buildwright/commands/bw-claw.md +332 -0
- package/templates/.buildwright/commands/bw-help.md +85 -0
- package/templates/.buildwright/commands/bw-new-feature.md +504 -0
- package/templates/.buildwright/commands/bw-quick.md +245 -0
- package/templates/.buildwright/commands/bw-ship.md +288 -0
- package/templates/.buildwright/commands/bw-verify.md +108 -0
- package/templates/.buildwright/steering/naming-conventions.md +40 -0
- package/templates/.buildwright/steering/product.md +16 -0
- package/templates/.buildwright/steering/quality-gates.md +35 -0
- package/templates/.buildwright/steering/tech.md +27 -0
- package/templates/.buildwright/tasks/TEMPLATE.md +79 -0
- package/templates/.github/workflows/quality-gates.yml +150 -0
- package/templates/BUILDWRIGHT.md +99 -0
- package/templates/CLAUDE.md +150 -0
- package/templates/Makefile +82 -0
- package/templates/docs/requirements/TEMPLATE.md +33 -0
- package/templates/env.example +11 -0
- package/templates/scripts/bump-version.sh +37 -0
- package/templates/scripts/hooks/post-checkout +24 -0
- package/templates/scripts/hooks/post-merge +14 -0
- package/templates/scripts/hooks/pre-commit +14 -0
- package/templates/scripts/install-hooks.sh +35 -0
- package/templates/scripts/sync-agents.sh +294 -0
- package/templates/scripts/validate-skill.sh +156 -0
package/README.md
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# buildwright
|
|
2
|
+
|
|
3
|
+
Agent-first autonomous development workflow. Ship code you don't read.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g buildwright
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Requires Node.js 18+.
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
# Navigate to your project
|
|
17
|
+
cd my-project
|
|
18
|
+
git init # if not already a git repo
|
|
19
|
+
|
|
20
|
+
# Set up Buildwright
|
|
21
|
+
buildwright init
|
|
22
|
+
|
|
23
|
+
# Customize for your project
|
|
24
|
+
nano .buildwright/steering/product.md # add product context
|
|
25
|
+
nano .buildwright/steering/tech.md # add tech stack + commands
|
|
26
|
+
|
|
27
|
+
# Start building
|
|
28
|
+
claude
|
|
29
|
+
> /bw-new-feature "Add user authentication"
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Commands
|
|
33
|
+
|
|
34
|
+
| Command | Description |
|
|
35
|
+
|---------|-------------|
|
|
36
|
+
| `buildwright init` | Set up Buildwright in the current project |
|
|
37
|
+
| `buildwright update` | Update commands/agents/claws from GitHub (preserves your steering docs) |
|
|
38
|
+
| `buildwright sync` | Re-sync `.buildwright/` to `.claude/`, `.opencode/`, `.cursor/rules/` |
|
|
39
|
+
|
|
40
|
+
## What `init` Does
|
|
41
|
+
|
|
42
|
+
1. Copies all Buildwright templates to your project:
|
|
43
|
+
- `.buildwright/` — canonical config (agents, claws, commands, steering)
|
|
44
|
+
- `scripts/` — sync and hook scripts
|
|
45
|
+
- `Makefile`, `CLAUDE.md`, `BUILDWRIGHT.md`
|
|
46
|
+
2. Makes scripts executable
|
|
47
|
+
3. Runs `make sync` to generate `.claude/`, `.opencode/`, `.cursor/rules/`
|
|
48
|
+
4. Installs git hooks for auto-sync on `.buildwright/` changes
|
|
49
|
+
|
|
50
|
+
## What `update` Does
|
|
51
|
+
|
|
52
|
+
Downloads the latest release from GitHub and updates:
|
|
53
|
+
- `.buildwright/commands/` — slash command definitions
|
|
54
|
+
- `.buildwright/agents/` — agent personas
|
|
55
|
+
- `.buildwright/claws/` — domain specialist prompts
|
|
56
|
+
- `CLAUDE.md` — agent instructions
|
|
57
|
+
|
|
58
|
+
**Preserves** your customizations in `.buildwright/steering/` (product.md, tech.md, etc.).
|
|
59
|
+
|
|
60
|
+
## Slash Commands (inside AI editors)
|
|
61
|
+
|
|
62
|
+
| Command | Purpose |
|
|
63
|
+
|---------|---------|
|
|
64
|
+
| `/bw-new-feature` | Full pipeline: research → spec → approve → build → ship |
|
|
65
|
+
| `/bw-quick` | Fast path for bug fixes, small tasks |
|
|
66
|
+
| `/bw-claw` | Cross-domain features (DB + API + UI) |
|
|
67
|
+
| `/bw-ship` | Quality gates + push + PR |
|
|
68
|
+
| `/bw-verify` | Quick typecheck/lint/test/build |
|
|
69
|
+
| `/bw-analyse` | Analyse brownfield codebase |
|
|
70
|
+
| `/bw-help` | Show all commands |
|
|
71
|
+
|
|
72
|
+
## Offline Support
|
|
73
|
+
|
|
74
|
+
All templates are bundled in the npm package — `buildwright init` works without internet access after installation. Use `buildwright update` to pull the latest templates from GitHub.
|
|
75
|
+
|
|
76
|
+
## More Information
|
|
77
|
+
|
|
78
|
+
See the [full documentation](https://github.com/raunakkathuria/buildwright) on GitHub.
|
|
79
|
+
|
|
80
|
+
## License
|
|
81
|
+
|
|
82
|
+
MIT
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const { Command } = require('commander');
|
|
5
|
+
const { init } = require('../src/commands/init');
|
|
6
|
+
const { update } = require('../src/commands/update');
|
|
7
|
+
const { sync } = require('../src/commands/sync');
|
|
8
|
+
|
|
9
|
+
const pkg = require('../package.json');
|
|
10
|
+
|
|
11
|
+
const program = new Command();
|
|
12
|
+
|
|
13
|
+
program
|
|
14
|
+
.name('buildwright')
|
|
15
|
+
.description('Agent-first autonomous development workflow')
|
|
16
|
+
.version(pkg.version);
|
|
17
|
+
|
|
18
|
+
program
|
|
19
|
+
.command('init')
|
|
20
|
+
.description('Set up Buildwright in the current project')
|
|
21
|
+
.action(() => {
|
|
22
|
+
init();
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
program
|
|
26
|
+
.command('update')
|
|
27
|
+
.description('Update commands, agents, and claws from GitHub (preserves steering docs)')
|
|
28
|
+
.action(async () => {
|
|
29
|
+
await update();
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
program
|
|
33
|
+
.command('sync')
|
|
34
|
+
.description('Re-sync .buildwright/ to .claude/, .opencode/, and .cursor/rules/')
|
|
35
|
+
.action(() => {
|
|
36
|
+
sync();
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
program.parse(process.argv);
|
package/package.json
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "buildwright",
|
|
3
|
+
"version": "0.0.3",
|
|
4
|
+
"description": "Agent-first autonomous development workflow. Ship code you don't read.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"engines": {
|
|
7
|
+
"node": ">=18.0.0"
|
|
8
|
+
},
|
|
9
|
+
"bin": {
|
|
10
|
+
"buildwright": "./bin/buildwright.js"
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"bin/",
|
|
14
|
+
"src/",
|
|
15
|
+
"templates/"
|
|
16
|
+
],
|
|
17
|
+
"scripts": {
|
|
18
|
+
"prepack": "node scripts/prepack.js",
|
|
19
|
+
"postpack": "node scripts/postpack.js"
|
|
20
|
+
},
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"commander": "^12.0.0"
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const { isGitRepo, isBuildwrightInstalled } = require('../utils/detect');
|
|
6
|
+
const { copyDir, chmodScripts } = require('../utils/copy-files');
|
|
7
|
+
const { runSync, runInstallHooks } = require('../utils/run-script');
|
|
8
|
+
|
|
9
|
+
// ANSI colours
|
|
10
|
+
const GREEN = '\x1b[32m';
|
|
11
|
+
const YELLOW = '\x1b[33m';
|
|
12
|
+
const CYAN = '\x1b[36m';
|
|
13
|
+
const BOLD = '\x1b[1m';
|
|
14
|
+
const RESET = '\x1b[0m';
|
|
15
|
+
|
|
16
|
+
function init() {
|
|
17
|
+
const cwd = process.cwd();
|
|
18
|
+
|
|
19
|
+
// 1. Check git repo
|
|
20
|
+
const hasGit = isGitRepo(cwd);
|
|
21
|
+
if (!hasGit) {
|
|
22
|
+
console.log(`${YELLOW}Note: No git repository detected. Git hooks will be skipped.${RESET}`);
|
|
23
|
+
console.log(`Run ${BOLD}git init && make install-hooks${RESET} later to enable auto-sync hooks.\n`);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// 2. Check for existing installation
|
|
27
|
+
if (isBuildwrightInstalled(cwd)) {
|
|
28
|
+
console.log(`${YELLOW}Buildwright is already installed in this directory.${RESET}`);
|
|
29
|
+
console.log(`To update commands/agents/claws to the latest version, run: ${BOLD}buildwright update${RESET}`);
|
|
30
|
+
process.exit(1);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
console.log(`${BOLD}Setting up Buildwright in ${cwd}...${RESET}\n`);
|
|
34
|
+
|
|
35
|
+
// 3. Copy templates → cwd
|
|
36
|
+
const templatesDir = path.join(__dirname, '..', '..', 'templates');
|
|
37
|
+
if (!fs.existsSync(templatesDir)) {
|
|
38
|
+
console.error('Error: templates directory not found in npm package. Reinstall buildwright.');
|
|
39
|
+
process.exit(1);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const templateEntries = fs.readdirSync(templatesDir);
|
|
43
|
+
for (const entry of templateEntries) {
|
|
44
|
+
const src = path.join(templatesDir, entry);
|
|
45
|
+
const dest = path.join(cwd, entry);
|
|
46
|
+
const stat = fs.statSync(fs.realpathSync(src));
|
|
47
|
+
|
|
48
|
+
if (stat.isDirectory()) {
|
|
49
|
+
console.log(` Copying ${entry}/`);
|
|
50
|
+
copyDir(src, dest);
|
|
51
|
+
} else {
|
|
52
|
+
console.log(` Copying ${entry}`);
|
|
53
|
+
fs.copyFileSync(fs.realpathSync(src), dest);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// 4. chmod +x scripts
|
|
58
|
+
chmodScripts(path.join(cwd, 'scripts'));
|
|
59
|
+
console.log('');
|
|
60
|
+
|
|
61
|
+
// 5. Run make sync
|
|
62
|
+
console.log(`${CYAN}Running make sync...${RESET}`);
|
|
63
|
+
const syncOk = runSync(cwd);
|
|
64
|
+
if (!syncOk) {
|
|
65
|
+
console.log(`${YELLOW}Warning: make sync failed. Run ${BOLD}make sync${RESET}${YELLOW} manually after setup.${RESET}`);
|
|
66
|
+
}
|
|
67
|
+
console.log('');
|
|
68
|
+
|
|
69
|
+
// 6. Run make install-hooks (only if inside a git repo)
|
|
70
|
+
if (hasGit) {
|
|
71
|
+
console.log(`${CYAN}Installing git hooks...${RESET}`);
|
|
72
|
+
const hooksOk = runInstallHooks(cwd);
|
|
73
|
+
if (!hooksOk) {
|
|
74
|
+
console.log(`${YELLOW}Warning: hook installation failed. Run ${BOLD}make install-hooks${RESET}${YELLOW} manually.${RESET}`);
|
|
75
|
+
}
|
|
76
|
+
console.log('');
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// 7. Success message
|
|
80
|
+
console.log(`${GREEN}${BOLD}Buildwright is ready!${RESET}\n`);
|
|
81
|
+
console.log('Next steps:');
|
|
82
|
+
console.log(` 1. Edit ${BOLD}.buildwright/steering/product.md${RESET} — add your product context`);
|
|
83
|
+
console.log(` 2. Edit ${BOLD}.buildwright/steering/tech.md${RESET} — add your tech stack`);
|
|
84
|
+
console.log(` 3. Open your AI editor and run ${BOLD}/bw-new-feature "your feature"${RESET}\n`);
|
|
85
|
+
console.log(`For help: ${BOLD}buildwright --help${RESET}`);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
module.exports = { init };
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { isBuildwrightInstalled } = require('../utils/detect');
|
|
4
|
+
const { runSync } = require('../utils/run-script');
|
|
5
|
+
|
|
6
|
+
const GREEN = '\x1b[32m';
|
|
7
|
+
const YELLOW = '\x1b[33m';
|
|
8
|
+
const CYAN = '\x1b[36m';
|
|
9
|
+
const BOLD = '\x1b[1m';
|
|
10
|
+
const RESET = '\x1b[0m';
|
|
11
|
+
|
|
12
|
+
function sync() {
|
|
13
|
+
const cwd = process.cwd();
|
|
14
|
+
|
|
15
|
+
if (!isBuildwrightInstalled(cwd)) {
|
|
16
|
+
console.log(`${YELLOW}Buildwright is not installed in this directory.${RESET}`);
|
|
17
|
+
console.log(`Run ${BOLD}buildwright init${RESET} first.`);
|
|
18
|
+
process.exit(1);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
console.log(`${CYAN}Syncing .buildwright/ to tool configs...${RESET}`);
|
|
22
|
+
const ok = runSync(cwd);
|
|
23
|
+
|
|
24
|
+
if (ok) {
|
|
25
|
+
console.log(`${GREEN}${BOLD}Sync complete!${RESET}`);
|
|
26
|
+
console.log('.claude/, .opencode/, .cursor/rules/, and AGENTS.md are up to date.');
|
|
27
|
+
} else {
|
|
28
|
+
console.log(`${YELLOW}Sync failed. Make sure make is installed or run scripts/sync-agents.sh directly.${RESET}`);
|
|
29
|
+
process.exit(1);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
module.exports = { sync };
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const https = require('https');
|
|
6
|
+
const { execSync } = require('child_process');
|
|
7
|
+
const { isBuildwrightInstalled } = require('../utils/detect');
|
|
8
|
+
const { copyDir } = require('../utils/copy-files');
|
|
9
|
+
const { runSync } = require('../utils/run-script');
|
|
10
|
+
|
|
11
|
+
// ANSI colours
|
|
12
|
+
const GREEN = '\x1b[32m';
|
|
13
|
+
const YELLOW = '\x1b[33m';
|
|
14
|
+
const CYAN = '\x1b[36m';
|
|
15
|
+
const BOLD = '\x1b[1m';
|
|
16
|
+
const RESET = '\x1b[0m';
|
|
17
|
+
|
|
18
|
+
const GITHUB_REPO = 'raunakkathuria/buildwright';
|
|
19
|
+
const UPDATE_DIRS = ['commands', 'agents', 'claws'];
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Download a URL following redirects. Returns a Buffer.
|
|
23
|
+
*/
|
|
24
|
+
function download(url) {
|
|
25
|
+
return new Promise((resolve, reject) => {
|
|
26
|
+
https.get(url, { headers: { 'User-Agent': 'buildwright-cli' } }, (res) => {
|
|
27
|
+
if (res.statusCode === 301 || res.statusCode === 302) {
|
|
28
|
+
return download(res.headers.location).then(resolve).catch(reject);
|
|
29
|
+
}
|
|
30
|
+
if (res.statusCode !== 200) {
|
|
31
|
+
return reject(new Error(`HTTP ${res.statusCode} for ${url}`));
|
|
32
|
+
}
|
|
33
|
+
const chunks = [];
|
|
34
|
+
res.on('data', chunk => chunks.push(chunk));
|
|
35
|
+
res.on('end', () => resolve(Buffer.concat(chunks)));
|
|
36
|
+
res.on('error', reject);
|
|
37
|
+
}).on('error', reject);
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Download and extract the GitHub tarball to a temp directory.
|
|
43
|
+
* Returns the path to the extracted root.
|
|
44
|
+
*/
|
|
45
|
+
async function downloadAndExtract() {
|
|
46
|
+
const tmpDir = fs.mkdtempSync(path.join(require('os').tmpdir(), 'buildwright-update-'));
|
|
47
|
+
const tarPath = path.join(tmpDir, 'buildwright.tar.gz');
|
|
48
|
+
|
|
49
|
+
console.log(`${CYAN}Downloading latest Buildwright from GitHub...${RESET}`);
|
|
50
|
+
const url = `https://api.github.com/repos/${GITHUB_REPO}/tarball/main`;
|
|
51
|
+
const data = await download(url);
|
|
52
|
+
fs.writeFileSync(tarPath, data);
|
|
53
|
+
|
|
54
|
+
console.log(`${CYAN}Extracting...${RESET}`);
|
|
55
|
+
execSync(`tar xzf "${tarPath}" -C "${tmpDir}"`, { stdio: 'pipe' });
|
|
56
|
+
|
|
57
|
+
// The tarball extracts to a directory like raunakkathuria-buildwright-<sha>/
|
|
58
|
+
const entries = fs.readdirSync(tmpDir).filter(e => e !== 'buildwright.tar.gz');
|
|
59
|
+
if (entries.length === 0) throw new Error('Tarball extraction produced no files');
|
|
60
|
+
|
|
61
|
+
const extractedRoot = path.join(tmpDir, entries[0]);
|
|
62
|
+
return { tmpDir, extractedRoot };
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async function update() {
|
|
66
|
+
const cwd = process.cwd();
|
|
67
|
+
|
|
68
|
+
if (!isBuildwrightInstalled(cwd)) {
|
|
69
|
+
console.log(`${YELLOW}Buildwright is not installed in this directory.${RESET}`);
|
|
70
|
+
console.log(`Run ${BOLD}buildwright init${RESET} first.`);
|
|
71
|
+
process.exit(1);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
console.log(`${BOLD}Updating Buildwright in ${cwd}...${RESET}\n`);
|
|
75
|
+
console.log(`Updating: ${UPDATE_DIRS.map(d => `.buildwright/${d}/`).join(', ')}`);
|
|
76
|
+
console.log(`Preserving: .buildwright/steering/ (your customizations)\n`);
|
|
77
|
+
|
|
78
|
+
let tmpDir;
|
|
79
|
+
try {
|
|
80
|
+
const result = await downloadAndExtract();
|
|
81
|
+
tmpDir = result.tmpDir;
|
|
82
|
+
const extractedRoot = result.extractedRoot;
|
|
83
|
+
|
|
84
|
+
const srcBuildwright = path.join(extractedRoot, '.buildwright');
|
|
85
|
+
if (!fs.existsSync(srcBuildwright)) {
|
|
86
|
+
throw new Error('Downloaded archive is missing .buildwright/ directory');
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Update only the specified directories
|
|
90
|
+
for (const dir of UPDATE_DIRS) {
|
|
91
|
+
const src = path.join(srcBuildwright, dir);
|
|
92
|
+
const dest = path.join(cwd, '.buildwright', dir);
|
|
93
|
+
if (!fs.existsSync(src)) {
|
|
94
|
+
console.log(` ${YELLOW}Skipping ${dir}/ (not found in latest release)${RESET}`);
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
console.log(` Updating .buildwright/${dir}/`);
|
|
98
|
+
// Remove old and replace
|
|
99
|
+
fs.rmSync(dest, { recursive: true, force: true });
|
|
100
|
+
copyDir(src, dest);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Also update CLAUDE.md if it exists in the download
|
|
104
|
+
const srcClaude = path.join(extractedRoot, 'CLAUDE.md');
|
|
105
|
+
if (fs.existsSync(srcClaude)) {
|
|
106
|
+
console.log(` Updating CLAUDE.md`);
|
|
107
|
+
fs.copyFileSync(srcClaude, path.join(cwd, 'CLAUDE.md'));
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
console.log('');
|
|
111
|
+
|
|
112
|
+
// Re-run sync
|
|
113
|
+
console.log(`${CYAN}Running make sync...${RESET}`);
|
|
114
|
+
const syncOk = runSync(cwd);
|
|
115
|
+
if (!syncOk) {
|
|
116
|
+
console.log(`${YELLOW}Warning: make sync failed. Run ${BOLD}make sync${RESET}${YELLOW} manually.${RESET}`);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
console.log('');
|
|
120
|
+
console.log(`${GREEN}${BOLD}Update complete!${RESET}`);
|
|
121
|
+
console.log('commands, agents, and claws are now up to date.');
|
|
122
|
+
console.log('Your steering docs (.buildwright/steering/) are unchanged.\n');
|
|
123
|
+
|
|
124
|
+
} catch (err) {
|
|
125
|
+
console.error(`\nUpdate failed: ${err.message}`);
|
|
126
|
+
console.error(`You can update manually by downloading from: https://github.com/${GITHUB_REPO}`);
|
|
127
|
+
process.exit(1);
|
|
128
|
+
} finally {
|
|
129
|
+
if (tmpDir) {
|
|
130
|
+
try { fs.rmSync(tmpDir, { recursive: true, force: true }); } catch { /* ignore */ }
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
module.exports = { update };
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Recursively copy src directory to dest directory.
|
|
8
|
+
* Resolves symlinks before copying so npm pack works correctly.
|
|
9
|
+
* @param {string} src - Source directory path
|
|
10
|
+
* @param {string} dest - Destination directory path
|
|
11
|
+
* @param {object} [opts]
|
|
12
|
+
* @param {string[]} [opts.skip] - Relative paths (from src) to skip
|
|
13
|
+
*/
|
|
14
|
+
function copyDir(src, dest, opts = {}) {
|
|
15
|
+
const skip = opts.skip || [];
|
|
16
|
+
const entries = fs.readdirSync(src, { withFileTypes: true });
|
|
17
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
18
|
+
|
|
19
|
+
for (const entry of entries) {
|
|
20
|
+
const srcPath = path.join(src, entry.name);
|
|
21
|
+
const destPath = path.join(dest, entry.name);
|
|
22
|
+
const relativePath = path.relative(src, srcPath);
|
|
23
|
+
|
|
24
|
+
if (skip.some(s => relativePath === s || relativePath.startsWith(s + path.sep))) {
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Resolve symlinks
|
|
29
|
+
const realSrcPath = fs.realpathSync(srcPath);
|
|
30
|
+
const stat = fs.statSync(realSrcPath);
|
|
31
|
+
|
|
32
|
+
if (stat.isDirectory()) {
|
|
33
|
+
copyDir(realSrcPath, destPath, opts);
|
|
34
|
+
} else {
|
|
35
|
+
fs.copyFileSync(realSrcPath, destPath);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Make all .sh files and hook scripts executable under a directory.
|
|
42
|
+
*/
|
|
43
|
+
function chmodScripts(dir) {
|
|
44
|
+
if (!fs.existsSync(dir)) return;
|
|
45
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
46
|
+
for (const entry of entries) {
|
|
47
|
+
const fullPath = path.join(dir, entry.name);
|
|
48
|
+
if (entry.isDirectory()) {
|
|
49
|
+
chmodScripts(fullPath);
|
|
50
|
+
} else if (entry.name.endsWith('.sh') || !entry.name.includes('.')) {
|
|
51
|
+
// executable if .sh or no extension (hook scripts)
|
|
52
|
+
try {
|
|
53
|
+
fs.chmodSync(fullPath, 0o755);
|
|
54
|
+
} catch {
|
|
55
|
+
// ignore on platforms that don't support chmod
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
module.exports = { copyDir, chmodScripts };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Check if current directory is a git repository.
|
|
8
|
+
* Walks up the directory tree looking for a .git directory.
|
|
9
|
+
*/
|
|
10
|
+
function isGitRepo(cwd) {
|
|
11
|
+
let dir = cwd;
|
|
12
|
+
while (true) {
|
|
13
|
+
if (fs.existsSync(path.join(dir, '.git'))) return true;
|
|
14
|
+
const parent = path.dirname(dir);
|
|
15
|
+
if (parent === dir) return false;
|
|
16
|
+
dir = parent;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Check if Buildwright is already installed in the given directory.
|
|
22
|
+
*/
|
|
23
|
+
function isBuildwrightInstalled(cwd) {
|
|
24
|
+
return fs.existsSync(path.join(cwd, '.buildwright'));
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
module.exports = { isGitRepo, isBuildwrightInstalled };
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { execSync, spawnSync } = require('child_process');
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Run a shell command synchronously in the given directory.
|
|
9
|
+
* Prints output as it runs. Returns true on success.
|
|
10
|
+
*/
|
|
11
|
+
function run(command, cwd) {
|
|
12
|
+
try {
|
|
13
|
+
execSync(command, { cwd, stdio: 'inherit' });
|
|
14
|
+
return true;
|
|
15
|
+
} catch {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Run make sync or fall back to running sync-agents.sh directly.
|
|
22
|
+
* Returns true on success.
|
|
23
|
+
*/
|
|
24
|
+
function runSync(cwd) {
|
|
25
|
+
const makefile = path.join(cwd, 'Makefile');
|
|
26
|
+
if (fs.existsSync(makefile)) {
|
|
27
|
+
if (run('make sync', cwd)) return true;
|
|
28
|
+
}
|
|
29
|
+
const syncScript = path.join(cwd, 'scripts', 'sync-agents.sh');
|
|
30
|
+
if (fs.existsSync(syncScript)) {
|
|
31
|
+
chmodX(syncScript);
|
|
32
|
+
return run(`bash "${syncScript}"`, cwd);
|
|
33
|
+
}
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Run make install-hooks or fall back to install-hooks.sh directly.
|
|
39
|
+
* Returns true on success.
|
|
40
|
+
*/
|
|
41
|
+
function runInstallHooks(cwd) {
|
|
42
|
+
const makefile = path.join(cwd, 'Makefile');
|
|
43
|
+
if (fs.existsSync(makefile)) {
|
|
44
|
+
if (run('make install-hooks', cwd)) return true;
|
|
45
|
+
}
|
|
46
|
+
const hooksScript = path.join(cwd, 'scripts', 'install-hooks.sh');
|
|
47
|
+
if (fs.existsSync(hooksScript)) {
|
|
48
|
+
chmodX(hooksScript);
|
|
49
|
+
return run(`bash "${hooksScript}"`, cwd);
|
|
50
|
+
}
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Make a file executable.
|
|
56
|
+
*/
|
|
57
|
+
function chmodX(filePath) {
|
|
58
|
+
try {
|
|
59
|
+
fs.chmodSync(filePath, 0o755);
|
|
60
|
+
} catch {
|
|
61
|
+
// ignore
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
module.exports = { run, runSync, runInstallHooks, chmodX };
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Agent Personas
|
|
2
|
+
|
|
3
|
+
This directory contains reusable agent personas that commands can reference.
|
|
4
|
+
|
|
5
|
+
## Available Agents
|
|
6
|
+
|
|
7
|
+
| Agent | File | Used By | Key Capabilities |
|
|
8
|
+
|-------|------|---------|-------------------|
|
|
9
|
+
| Architect | `architect.md` | `/bw-claw` | Decomposes cross-domain work, defines interfaces, coordinates claws |
|
|
10
|
+
| Staff Engineer | `staff-engineer.md` | `/bw-new-feature`, `/bw-ship` | Confidence scoring (>=80), HIGH SIGNAL criteria, false-positive exclusions |
|
|
11
|
+
| Security Engineer | `security-engineer.md` | `/bw-ship` | Confidence scoring (>=0.8), exploit scenarios, hard exclusions |
|
|
12
|
+
|
|
13
|
+
## Claw Architecture
|
|
14
|
+
|
|
15
|
+
For domain-specialist agents (claws), see `.buildwright/claws/`.
|
|
16
|
+
|
|
17
|
+
The Architect agent coordinates claws:
|
|
18
|
+
```
|
|
19
|
+
Architect (Brain)
|
|
20
|
+
|
|
|
21
|
+
+---------+---------+
|
|
22
|
+
| | |
|
|
23
|
+
UI Claw API Claw DB Claw
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Adding New Agents
|
|
27
|
+
|
|
28
|
+
1. Create a new file: `[role-name].md`
|
|
29
|
+
2. Define:
|
|
30
|
+
- Mindset and expertise
|
|
31
|
+
- What they look for
|
|
32
|
+
- Output format
|
|
33
|
+
- Rules/guidelines
|
|
34
|
+
3. Reference in commands via: `Read and adopt persona from .buildwright/agents/[role-name].md`
|
|
35
|
+
|
|
36
|
+
## Planned Agents (Future)
|
|
37
|
+
|
|
38
|
+
| Agent | Purpose |
|
|
39
|
+
|-------|---------|
|
|
40
|
+
| QA Engineer | Test coverage review, edge case identification |
|
|
41
|
+
| Performance Engineer | Performance review, bottleneck identification |
|
|
42
|
+
| DevOps Engineer | Infrastructure review, deployment concerns |
|
|
43
|
+
| Database Engineer | Schema review, query optimization |
|
|
44
|
+
| UX Engineer | API design review, developer experience |
|
|
45
|
+
| Technical Writer | Documentation quality |
|
|
46
|
+
|
|
47
|
+
## Agent Design Principles
|
|
48
|
+
|
|
49
|
+
1. **Specific expertise** — Each agent has a focused domain
|
|
50
|
+
2. **Consistent output** — Predictable format for parsing/automation
|
|
51
|
+
3. **Actionable feedback** — Problems come with solutions
|
|
52
|
+
4. **Severity levels** — Distinguish blocking from advisory
|
|
53
|
+
5. **Context-aware** — Adapt to project type and risk level
|