brn-toolkit 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/GEMINI.md +92 -0
- package/README.md +145 -0
- package/cli/brn.ts +301 -0
- package/dist/cli/brn.js +274 -0
- package/dist/lib/utils.js +167 -0
- package/dist/skills/github/scripts/create_pr.js +24 -0
- package/dist/skills/github/scripts/get_repo_info.js +23 -0
- package/dist/skills/github/scripts/list_prs.js +27 -0
- package/dist/skills/github/scripts/list_repos.js +39 -0
- package/dist/skills/jira/scripts/add_comment.js +36 -0
- package/dist/skills/jira/scripts/get_ticket.js +45 -0
- package/dist/skills/jira/scripts/list_tickets.js +42 -0
- package/dist/skills/jira/scripts/update_ticket.js +30 -0
- package/dist/skills/workflow/scripts/start.js +75 -0
- package/dist/skills/workspace-manager/scripts/configure_workspace.js +59 -0
- package/dist/skills/workspace-manager/scripts/create_workspace.js +60 -0
- package/lib/utils.ts +236 -0
- package/package.json +46 -0
- package/skills/git-worktree/SKILL.md +49 -0
- package/skills/git-worktree/scripts/clone_repo.sh +53 -0
- package/skills/git-worktree/scripts/create_worktree.sh +66 -0
- package/skills/git-worktree/scripts/list_worktrees.sh +39 -0
- package/skills/git-worktree/scripts/remove_worktree.sh +47 -0
- package/skills/github/SKILL.md +51 -0
- package/skills/github/references/api_patterns.md +36 -0
- package/skills/github/scripts/create_pr.ts +38 -0
- package/skills/github/scripts/get_repo_info.ts +39 -0
- package/skills/github/scripts/list_prs.ts +45 -0
- package/skills/github/scripts/list_repos.ts +54 -0
- package/skills/jira/SKILL.md +50 -0
- package/skills/jira/references/api_patterns.md +59 -0
- package/skills/jira/scripts/add_comment.ts +41 -0
- package/skills/jira/scripts/get_ticket.ts +71 -0
- package/skills/jira/scripts/list_tickets.ts +64 -0
- package/skills/jira/scripts/update_ticket.ts +50 -0
- package/skills/workflow/SKILL.md +94 -0
- package/skills/workflow/references/coding_workflow.md +88 -0
- package/skills/workflow/references/planning_workflow.md +96 -0
- package/skills/workflow/references/review_workflow.md +104 -0
- package/skills/workflow/scripts/start.ts +93 -0
- package/skills/workspace-manager/SKILL.md +49 -0
- package/skills/workspace-manager/scripts/configure_workspace.sh +87 -0
- package/skills/workspace-manager/scripts/configure_workspace.ts +70 -0
- package/skills/workspace-manager/scripts/create_workspace.sh +66 -0
- package/skills/workspace-manager/scripts/create_workspace.ts +74 -0
- package/skills/workspace-manager/scripts/get_active_workspace.sh +24 -0
- package/skills/workspace-manager/scripts/list_workspaces.sh +31 -0
- package/skills/workspace-manager/scripts/switch_workspace.sh +38 -0
package/GEMINI.md
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# BRN - AI Developer Workflow Toolkit
|
|
2
|
+
|
|
3
|
+
**BRN** is a modular skills toolkit designed to supercharge AI assistants (like Claude Code and GitHub Copilot CLI) by automating complex developer workflows. It bridges the gap between high-level AI intent and low-level system operations (Git, GitHub API, JIRA API).
|
|
4
|
+
|
|
5
|
+
## Project Overview
|
|
6
|
+
|
|
7
|
+
* **Goal**: Centralize tools, agents, and skills to automate daily dev workflows (planning, coding, testing, PRs).
|
|
8
|
+
* **Core Concepts**:
|
|
9
|
+
* **Workspaces**: Isolated configurations (tokens, directories) for different contexts (e.g., "personal" vs "work").
|
|
10
|
+
* **Skills**: Modular units of functionality (e.g., "github", "jira", "git-worktree").
|
|
11
|
+
* **Git Worktrees**: Efficiently manages multiple branches/features without re-cloning repositories.
|
|
12
|
+
* **Tech Stack**:
|
|
13
|
+
* **Runtime**: Node.js
|
|
14
|
+
* **Language**: TypeScript
|
|
15
|
+
* **Execution**: `tsx` (TypeScript Execute)
|
|
16
|
+
* **Shell Integration**: `zx` (for seamless shell command execution)
|
|
17
|
+
* **Configuration**: YAML (`~/.brn/config.yaml`)
|
|
18
|
+
|
|
19
|
+
## Architecture
|
|
20
|
+
|
|
21
|
+
The project is structured into a core CLI and a set of modular skills.
|
|
22
|
+
|
|
23
|
+
```text
|
|
24
|
+
/
|
|
25
|
+
├── cli/ # Core CLI logic
|
|
26
|
+
│ └── brn.ts # Main entry point (setup, workspace management)
|
|
27
|
+
├── skills/ # Modular skills directory
|
|
28
|
+
│ ├── github/ # GitHub integration
|
|
29
|
+
│ ├── jira/ # JIRA integration
|
|
30
|
+
│ ├── git-worktree/ # Git worktree management
|
|
31
|
+
│ ├── workflow/ # End-to-end workflow orchestration
|
|
32
|
+
│ └── workspace-manager/ # Workspace configuration scripts
|
|
33
|
+
├── lib/ # Shared utilities
|
|
34
|
+
│ └── utils.ts
|
|
35
|
+
└── package.json # Dependencies (zx, yaml, tsx)
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Skills Structure
|
|
39
|
+
Each skill typically contains:
|
|
40
|
+
* `SKILL.md`: Documentation for the AI/User describing the skill's purpose and usage.
|
|
41
|
+
* `scripts/`: Executable scripts (TypeScript or Shell) that perform the actual tasks.
|
|
42
|
+
* `references/`: (Optional) Helper docs like API patterns.
|
|
43
|
+
|
|
44
|
+
## Building and Running
|
|
45
|
+
|
|
46
|
+
### Prerequisites
|
|
47
|
+
* Node.js 18+
|
|
48
|
+
* Git
|
|
49
|
+
|
|
50
|
+
### Installation
|
|
51
|
+
1. **Install Dependencies**:
|
|
52
|
+
```bash
|
|
53
|
+
npm install
|
|
54
|
+
```
|
|
55
|
+
2. **Link Globally**:
|
|
56
|
+
```bash
|
|
57
|
+
npm link
|
|
58
|
+
```
|
|
59
|
+
This makes the `brn` command available globally.
|
|
60
|
+
|
|
61
|
+
### Usage
|
|
62
|
+
* **Setup**: Run the interactive wizard to configure workspaces.
|
|
63
|
+
```bash
|
|
64
|
+
brn setup
|
|
65
|
+
```
|
|
66
|
+
* **Workspace Management**:
|
|
67
|
+
```bash
|
|
68
|
+
brn workspace list
|
|
69
|
+
brn workspace switch <name>
|
|
70
|
+
```
|
|
71
|
+
* **Running Skills Manually**:
|
|
72
|
+
Scripts can be run directly via `npm run` (defined in `package.json`) or `npx tsx`:
|
|
73
|
+
```bash
|
|
74
|
+
# Example: List GitHub repos
|
|
75
|
+
npm run github:repos -- <org_name>
|
|
76
|
+
# OR
|
|
77
|
+
npx tsx skills/github/scripts/list_repos.ts <org_name>
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Configuration
|
|
81
|
+
|
|
82
|
+
Configuration is stored in `~/.brn/config.yaml`. It manages:
|
|
83
|
+
* **Active Workspace**: The currently selected context.
|
|
84
|
+
* **Workspaces**: Key-value map of workspace names to configs (paths, tokens).
|
|
85
|
+
* **Automation Flags**: Safety toggles (default: OFF) for actions like auto-pushing or auto-commenting.
|
|
86
|
+
|
|
87
|
+
## Development Conventions
|
|
88
|
+
|
|
89
|
+
* **TypeScript**: Use TypeScript for all new logic. Use `tsx` for execution.
|
|
90
|
+
* **Shell Integration**: Use `zx` (`import { $ } from "zx"`) for running shell commands within TypeScript files.
|
|
91
|
+
* **Modularity**: Keep skills self-contained. If logic is shared, put it in `lib/utils.ts`.
|
|
92
|
+
* **Safety First**: All mutative actions (push, delete, update) should be gated by automation flags or explicit user confirmation.
|
package/README.md
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# BRN - AI Developer Workflow Toolkit
|
|
2
|
+
|
|
3
|
+
**BRN** is a modular skills toolkit designed to supercharge AI assistants and developers by automating complex workflows. It bridges the gap between high-level intent (e.g., "Start working on ticket PROJ-123") and low-level system operations (Git, GitHub API, JIRA API).
|
|
4
|
+
|
|
5
|
+
## Core Concepts
|
|
6
|
+
|
|
7
|
+
* **Workspaces**: Isolated environments for different contexts (e.g., "personal", "work"). Each workspace has its own configuration (API tokens, root directory).
|
|
8
|
+
* **Skills**: Modular units of functionality. Each skill (e.g., `github`, `jira`, `git-worktree`) provides a set of specific commands.
|
|
9
|
+
* **Git Worktrees**: The toolkit manages repositories using the Git worktree pattern, allowing you to work on multiple branches simultaneously in sibling directories without re-cloning.
|
|
10
|
+
* **CLI First**: All functionality is exposed through a unified `brn` CLI.
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
### Prerequisites
|
|
15
|
+
* **Node.js** (v18 or later)
|
|
16
|
+
* **Git**
|
|
17
|
+
|
|
18
|
+
### Setup
|
|
19
|
+
1. **Clone the repository**:
|
|
20
|
+
```bash
|
|
21
|
+
git clone https://github.com/zfael/brn.git ~/.brn-toolkit
|
|
22
|
+
cd ~/.brn-toolkit
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
2. **Install dependencies**:
|
|
26
|
+
```bash
|
|
27
|
+
npm install
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
3. **Link globally**:
|
|
31
|
+
```bash
|
|
32
|
+
npm link
|
|
33
|
+
```
|
|
34
|
+
This makes the `brn` command available globally in your terminal.
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## Quick Start
|
|
39
|
+
|
|
40
|
+
### 1. Configure BRN
|
|
41
|
+
Run the interactive setup wizard to create your first workspace and configure API tokens.
|
|
42
|
+
```bash
|
|
43
|
+
brn setup
|
|
44
|
+
```
|
|
45
|
+
This will create `~/.brn/config.yaml` and prompt you for:
|
|
46
|
+
- Workspace name (e.g., "personal")
|
|
47
|
+
- Work directory (where code will be stored)
|
|
48
|
+
- GitHub & JIRA tokens (optional but recommended)
|
|
49
|
+
|
|
50
|
+
### 2. Start a Task
|
|
51
|
+
To start working on a JIRA ticket:
|
|
52
|
+
```bash
|
|
53
|
+
brn start PROJ-123
|
|
54
|
+
```
|
|
55
|
+
This single command:
|
|
56
|
+
1. Fetches ticket details from JIRA.
|
|
57
|
+
2. Finds or clones the correct repository.
|
|
58
|
+
3. Creates a new Git worktree for the feature.
|
|
59
|
+
4. Updates the JIRA ticket status to "In Progress".
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## Usage Guide
|
|
64
|
+
|
|
65
|
+
The CLI follows the pattern: `brn <skill> <command> [arguments]`
|
|
66
|
+
|
|
67
|
+
### 🛠 Workflow
|
|
68
|
+
High-level orchestration of development tasks.
|
|
69
|
+
- `brn start <ticket_id>`: Start working on a ticket (shortcut for `brn workflow start`).
|
|
70
|
+
|
|
71
|
+
### 🐙 GitHub (`brn github ...`)
|
|
72
|
+
- `list_repos [org]`: List repositories.
|
|
73
|
+
- `get_repo_info <owner/repo>`: Get details about a repo.
|
|
74
|
+
- `create_pr <owner/repo> <head> <base> <title>`: Create a Pull Request.
|
|
75
|
+
- `list_prs <owner/repo>`: List open PRs.
|
|
76
|
+
|
|
77
|
+
### 📋 JIRA (`brn jira ...`)
|
|
78
|
+
- `list_tickets [status]`: List tickets assigned to you.
|
|
79
|
+
- `get_ticket <key>`: Get ticket details.
|
|
80
|
+
- `update_ticket <key> <status>`: Update ticket status.
|
|
81
|
+
- `add_comment <key> <comment>`: Add a comment to a ticket.
|
|
82
|
+
|
|
83
|
+
### 🌳 Git Worktree (`brn git-worktree ...`)
|
|
84
|
+
- `clone_repo <url> [name]`: Clone a repo for worktree usage.
|
|
85
|
+
- `create_worktree <repo> <branch>`: Create a new worktree.
|
|
86
|
+
- `list_worktrees <repo>`: List active worktrees.
|
|
87
|
+
- `remove_worktree <repo> <branch>`: Remove a worktree.
|
|
88
|
+
|
|
89
|
+
### ⚙️ Workspace (`brn workspace ...`)
|
|
90
|
+
- `list`: List all configured workspaces.
|
|
91
|
+
- `switch <name>`: Switch the active workspace.
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## Configuration
|
|
96
|
+
|
|
97
|
+
Configuration is stored in `~/.brn/config.yaml`.
|
|
98
|
+
|
|
99
|
+
```yaml
|
|
100
|
+
version: "1.0"
|
|
101
|
+
active_workspace: personal
|
|
102
|
+
workspaces:
|
|
103
|
+
personal:
|
|
104
|
+
path: /Users/me/dev/personal
|
|
105
|
+
github_token: ghp_...
|
|
106
|
+
jira_url: https://myorg.atlassian.net
|
|
107
|
+
jira_email: me@myorg.com
|
|
108
|
+
jira_token: ATATT...
|
|
109
|
+
automation:
|
|
110
|
+
github_auto_push: false
|
|
111
|
+
jira_auto_transition: false
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Automation Flags
|
|
115
|
+
For safety, automated actions (like pushing code or updating JIRA) are **disabled by default**. You can enable them in `config.yaml` or during `brn setup`.
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## Architecture
|
|
120
|
+
|
|
121
|
+
```text
|
|
122
|
+
/
|
|
123
|
+
├── cli/ # Core CLI logic (brn.ts)
|
|
124
|
+
├── skills/ # Modular skills
|
|
125
|
+
│ ├── github/ # GitHub integration
|
|
126
|
+
│ ├── jira/ # JIRA integration
|
|
127
|
+
│ ├── git-worktree/ # Git worktree management
|
|
128
|
+
│ ├── workflow/ # Orchestration
|
|
129
|
+
│ └── workspace-manager/
|
|
130
|
+
├── lib/ # Shared utilities
|
|
131
|
+
└── package.json
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## Development
|
|
135
|
+
|
|
136
|
+
### Tech Stack
|
|
137
|
+
* **Runtime**: Node.js
|
|
138
|
+
* **Language**: TypeScript
|
|
139
|
+
* **Execution**: `tsx` (TypeScript Execute)
|
|
140
|
+
* **Shell Integration**: `zx` (Google's tool for writing shell scripts in JS)
|
|
141
|
+
|
|
142
|
+
### Conventions
|
|
143
|
+
1. **TypeScript First**: All new scripts should be written in TypeScript using `zx`.
|
|
144
|
+
2. **Modularity**: Skills should be self-contained in `skills/<skill_name>`.
|
|
145
|
+
3. **Safety**: Destructive actions must be gated by automation flags or confirmation prompts.
|
package/cli/brn.ts
ADDED
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* BRN-Toolkit CLI - Main entry point
|
|
4
|
+
* Usage: brn <command> [options]
|
|
5
|
+
*/
|
|
6
|
+
import { $ } from "zx";
|
|
7
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync } from "fs";
|
|
8
|
+
import { homedir } from "os";
|
|
9
|
+
import { join, dirname } from "path";
|
|
10
|
+
import { fileURLToPath } from "url";
|
|
11
|
+
import * as readline from "readline";
|
|
12
|
+
import YAML from "yaml";
|
|
13
|
+
|
|
14
|
+
$.verbose = false;
|
|
15
|
+
|
|
16
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
17
|
+
const __dirname = dirname(__filename);
|
|
18
|
+
|
|
19
|
+
// Handle both source (cli/brn.ts) and compiled (dist/cli/brn.js) locations
|
|
20
|
+
const isCompiled = __dirname.includes(join("dist", "cli"));
|
|
21
|
+
const PROJECT_ROOT = isCompiled ? join(__dirname, "..", "..") : join(__dirname, "..");
|
|
22
|
+
|
|
23
|
+
const BRN_DIR = join(homedir(), ".brn");
|
|
24
|
+
const CONFIG_FILE = join(BRN_DIR, "config.yaml");
|
|
25
|
+
|
|
26
|
+
// Simple readline interface for prompts
|
|
27
|
+
function prompt(question: string): Promise<string> {
|
|
28
|
+
const rl = readline.createInterface({
|
|
29
|
+
input: process.stdin,
|
|
30
|
+
output: process.stdout,
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
return new Promise((resolve) => {
|
|
34
|
+
rl.question(question, (answer) => {
|
|
35
|
+
rl.close();
|
|
36
|
+
resolve(answer.trim());
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
async function runSkill(skill: string, script: string, args: string[]) {
|
|
42
|
+
// Determine where to look for scripts
|
|
43
|
+
// Prefer dist/skills/.../*.js for speed, fallback to skills/.../*.ts
|
|
44
|
+
const distScriptsDir = join(PROJECT_ROOT, "dist", "skills", skill, "scripts");
|
|
45
|
+
const srcScriptsDir = join(PROJECT_ROOT, "skills", skill, "scripts");
|
|
46
|
+
|
|
47
|
+
const jsPath = join(distScriptsDir, `${script}.js`);
|
|
48
|
+
const tsPath = join(srcScriptsDir, `${script}.ts`);
|
|
49
|
+
const shPath = join(srcScriptsDir, `${script}.sh`);
|
|
50
|
+
|
|
51
|
+
// Enable verbose to show output of the child script
|
|
52
|
+
const previousVerbose = $.verbose;
|
|
53
|
+
$.verbose = true;
|
|
54
|
+
|
|
55
|
+
try {
|
|
56
|
+
if (existsSync(jsPath)) {
|
|
57
|
+
// Run compiled JS with node
|
|
58
|
+
await $`node ${jsPath} ${args}`;
|
|
59
|
+
} else if (existsSync(tsPath)) {
|
|
60
|
+
// Run TS with tsx
|
|
61
|
+
await $`npx tsx ${tsPath} ${args}`;
|
|
62
|
+
} else if (existsSync(shPath)) {
|
|
63
|
+
// Run shell
|
|
64
|
+
await $`bash ${shPath} ${args}`;
|
|
65
|
+
} else {
|
|
66
|
+
// Try without extension in src
|
|
67
|
+
const exactPath = join(srcScriptsDir, script);
|
|
68
|
+
if (existsSync(exactPath)) {
|
|
69
|
+
if (script.endsWith(".sh")) await $`bash ${exactPath} ${args}`;
|
|
70
|
+
else await $`npx tsx ${exactPath} ${args}`;
|
|
71
|
+
} else {
|
|
72
|
+
console.error(`Skill script not found: ${skill}/${script}`);
|
|
73
|
+
process.exit(1);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
} finally {
|
|
77
|
+
$.verbose = previousVerbose;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async function setup() {
|
|
82
|
+
console.log("");
|
|
83
|
+
console.log("🚀 BRN Setup Wizard");
|
|
84
|
+
console.log("===================");
|
|
85
|
+
console.log("");
|
|
86
|
+
|
|
87
|
+
// Create config directory
|
|
88
|
+
if (!existsSync(BRN_DIR)) {
|
|
89
|
+
mkdirSync(BRN_DIR, { recursive: true });
|
|
90
|
+
console.log(`✓ Created ${BRN_DIR}`);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Check for existing config
|
|
94
|
+
let config: any = { version: "1.0", active_workspace: "", workspaces: {} };
|
|
95
|
+
if (existsSync(CONFIG_FILE)) {
|
|
96
|
+
config = YAML.parse(readFileSync(CONFIG_FILE, "utf-8"));
|
|
97
|
+
console.log(`✓ Found existing config with ${Object.keys(config.workspaces).length} workspace(s)`);
|
|
98
|
+
console.log("");
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Workspace name
|
|
102
|
+
const defaultName = Object.keys(config.workspaces).length === 0 ? "personal" : "";
|
|
103
|
+
const name = await prompt(`Workspace name [${defaultName}]: `) || defaultName;
|
|
104
|
+
|
|
105
|
+
if (!name) {
|
|
106
|
+
console.log("❌ Workspace name is required");
|
|
107
|
+
process.exit(1);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Work directory
|
|
111
|
+
const defaultPath = join(homedir(), "dev", name, "auto");
|
|
112
|
+
const workDir = await prompt(`Work directory [${defaultPath}]: `) || defaultPath;
|
|
113
|
+
|
|
114
|
+
// GitHub token (optional)
|
|
115
|
+
console.log("");
|
|
116
|
+
console.log("📦 GitHub Configuration (optional, press Enter to skip)");
|
|
117
|
+
const githubToken = await prompt("GitHub token: ");
|
|
118
|
+
const githubOrg = await prompt("Default GitHub Organization/User: ");
|
|
119
|
+
|
|
120
|
+
// JIRA config (optional)
|
|
121
|
+
console.log("");
|
|
122
|
+
console.log("📋 JIRA Configuration (optional, press Enter to skip)");
|
|
123
|
+
const jiraUrl = await prompt("JIRA URL (e.g., https://company.atlassian.net): ");
|
|
124
|
+
let jiraEmail = "";
|
|
125
|
+
let jiraToken = "";
|
|
126
|
+
if (jiraUrl) {
|
|
127
|
+
jiraEmail = await prompt("JIRA email: ");
|
|
128
|
+
jiraToken = await prompt("JIRA API token: ");
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Automation settings
|
|
132
|
+
console.log("");
|
|
133
|
+
console.log("⚙️ Automation Settings");
|
|
134
|
+
console.log(" By default, all automation is OFF for safety.");
|
|
135
|
+
const enableAuto = await prompt("Enable any automation? (y/N): ");
|
|
136
|
+
|
|
137
|
+
let automation: Record<string, boolean> = {
|
|
138
|
+
github_auto_push: false,
|
|
139
|
+
github_auto_pr: false,
|
|
140
|
+
jira_auto_transition: false,
|
|
141
|
+
jira_auto_comment: false,
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
if (enableAuto.toLowerCase() === "y") {
|
|
145
|
+
const autoPush = await prompt(" Auto-push commits? (y/N): ");
|
|
146
|
+
const autoPr = await prompt(" Auto-create PRs? (y/N): ");
|
|
147
|
+
const autoTransition = await prompt(" Auto-update JIRA status? (y/N): ");
|
|
148
|
+
const autoComment = await prompt(" Auto-add JIRA comments? (y/N): ");
|
|
149
|
+
|
|
150
|
+
automation = {
|
|
151
|
+
github_auto_push: autoPush.toLowerCase() === "y",
|
|
152
|
+
github_auto_pr: autoPr.toLowerCase() === "y",
|
|
153
|
+
jira_auto_transition: autoTransition.toLowerCase() === "y",
|
|
154
|
+
jira_auto_comment: autoComment.toLowerCase() === "y",
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Build workspace config
|
|
159
|
+
const workspace: any = {
|
|
160
|
+
path: workDir,
|
|
161
|
+
automation,
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
if (githubToken) workspace.github_token = githubToken;
|
|
165
|
+
if (githubOrg) workspace.github_org = githubOrg;
|
|
166
|
+
if (jiraUrl) {
|
|
167
|
+
workspace.jira_url = jiraUrl;
|
|
168
|
+
workspace.jira_email = jiraEmail;
|
|
169
|
+
workspace.jira_token = jiraToken;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Save config
|
|
173
|
+
config.workspaces[name] = workspace;
|
|
174
|
+
if (!config.active_workspace) {
|
|
175
|
+
config.active_workspace = name;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
writeFileSync(CONFIG_FILE, YAML.stringify(config));
|
|
179
|
+
|
|
180
|
+
// Create work directory
|
|
181
|
+
if (!existsSync(workDir)) {
|
|
182
|
+
mkdirSync(workDir, { recursive: true });
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
console.log("");
|
|
186
|
+
console.log("✅ Setup complete!");
|
|
187
|
+
console.log("");
|
|
188
|
+
console.log(` Workspace: ${name}`);
|
|
189
|
+
console.log(` Work dir: ${workDir}`);
|
|
190
|
+
console.log(` Config: ${CONFIG_FILE}`);
|
|
191
|
+
console.log("");
|
|
192
|
+
console.log("Next steps:");
|
|
193
|
+
console.log(" • Use 'brn workspace list' to see workspaces");
|
|
194
|
+
console.log(" • Use 'brn workspace switch <name>' to change workspace");
|
|
195
|
+
console.log(" • Ask your AI assistant to 'list my JIRA tickets'");
|
|
196
|
+
console.log("");
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
async function workspaceList() {
|
|
200
|
+
if (!existsSync(CONFIG_FILE)) {
|
|
201
|
+
console.log("No workspaces configured. Run: brn setup");
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
const config = YAML.parse(readFileSync(CONFIG_FILE, "utf-8"));
|
|
206
|
+
const active = config.active_workspace;
|
|
207
|
+
|
|
208
|
+
console.log("Workspaces:");
|
|
209
|
+
console.log("===========");
|
|
210
|
+
|
|
211
|
+
for (const [name, ws] of Object.entries(config.workspaces)) {
|
|
212
|
+
const workspace = ws as any;
|
|
213
|
+
const marker = name === active ? "* " : " ";
|
|
214
|
+
const activeLabel = name === active ? " [ACTIVE]" : "";
|
|
215
|
+
console.log(`${marker}${name} (${workspace.path})${activeLabel}`);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
async function workspaceSwitch(name: string) {
|
|
220
|
+
if (!existsSync(CONFIG_FILE)) {
|
|
221
|
+
console.log("No workspaces configured. Run: brn setup");
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
const config = YAML.parse(readFileSync(CONFIG_FILE, "utf-8"));
|
|
226
|
+
|
|
227
|
+
if (!config.workspaces[name]) {
|
|
228
|
+
console.log(`Workspace '${name}' not found.`);
|
|
229
|
+
console.log("Available:", Object.keys(config.workspaces).join(", "));
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
config.active_workspace = name;
|
|
234
|
+
writeFileSync(CONFIG_FILE, YAML.stringify(config));
|
|
235
|
+
console.log(`✓ Switched to workspace '${name}'`);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
function showHelp() {
|
|
239
|
+
console.log(`
|
|
240
|
+
BRN - AI Developer Workflow Toolkit
|
|
241
|
+
|
|
242
|
+
Usage:
|
|
243
|
+
brn <command> [options]
|
|
244
|
+
brn <skill> <script> [args]
|
|
245
|
+
|
|
246
|
+
Commands:
|
|
247
|
+
start <ticket> Shortcut for workflow start <ticket>
|
|
248
|
+
setup Interactive setup wizard
|
|
249
|
+
workspace list List all workspaces
|
|
250
|
+
workspace switch <n> Switch to workspace <n>
|
|
251
|
+
help Show this help
|
|
252
|
+
|
|
253
|
+
Skills:
|
|
254
|
+
github <script> Run a GitHub skill script (e.g., list_repos)
|
|
255
|
+
jira <script> Run a JIRA skill script (e.g., list_tickets)
|
|
256
|
+
git-worktree <script> Run a Git Worktree skill script (e.g., clone_repo)
|
|
257
|
+
|
|
258
|
+
Examples:
|
|
259
|
+
brn start PROJ-123
|
|
260
|
+
brn github list_repos
|
|
261
|
+
brn jira list_tickets
|
|
262
|
+
brn workspace switch work
|
|
263
|
+
`);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// Main
|
|
267
|
+
const args = process.argv.slice(2);
|
|
268
|
+
const command = args[0];
|
|
269
|
+
|
|
270
|
+
switch (command) {
|
|
271
|
+
case "start":
|
|
272
|
+
await runSkill("workflow", "start", args.slice(1));
|
|
273
|
+
break;
|
|
274
|
+
case "setup":
|
|
275
|
+
await setup();
|
|
276
|
+
break;
|
|
277
|
+
case "workspace":
|
|
278
|
+
if (args[1] === "list") {
|
|
279
|
+
await workspaceList();
|
|
280
|
+
} else if (args[1] === "switch" && args[2]) {
|
|
281
|
+
await workspaceSwitch(args[2]);
|
|
282
|
+
} else {
|
|
283
|
+
console.log("Usage: brn workspace [list|switch <name>]");
|
|
284
|
+
}
|
|
285
|
+
break;
|
|
286
|
+
case "help":
|
|
287
|
+
case "--help":
|
|
288
|
+
case "-h":
|
|
289
|
+
case undefined:
|
|
290
|
+
showHelp();
|
|
291
|
+
break;
|
|
292
|
+
default:
|
|
293
|
+
// Generic skill runner: brn <skill> <script> [...args]
|
|
294
|
+
if (command && args[1]) {
|
|
295
|
+
await runSkill(command, args[1], args.slice(2));
|
|
296
|
+
} else {
|
|
297
|
+
console.log(`Unknown command: ${command}`);
|
|
298
|
+
showHelp();
|
|
299
|
+
process.exit(1);
|
|
300
|
+
}
|
|
301
|
+
}
|