claudeboard 2.15.4 → 3.1.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/cli.js CHANGED
@@ -1,251 +1,219 @@
1
1
  #!/usr/bin/env node
2
+ // bin/cli.js
3
+ const path = require('path');
4
+ const fs = require('fs');
5
+ const chalk = require('chalk');
6
+
7
+ const PKG_VERSION = '3.1.0';
8
+
9
+ // ─────────────────────────────────────────────────────────────────
10
+ // Helpers
11
+ // ─────────────────────────────────────────────────────────────────
12
+ function header(subtitle) {
13
+ console.log(chalk.bold.hex('#e3c69a')('ClaudeBoard v3 ✦') + (subtitle ? chalk.dim(' ' + subtitle) : ''));
14
+ console.log(chalk.dim('Visual orchestrator for Claude Code agent teams'));
15
+ console.log('');
16
+ }
2
17
 
3
- import { program } from "commander";
4
- import chalk from "chalk";
5
- import ora from "ora";
6
- import { fileURLToPath } from "url";
7
- import path from "path";
8
- import fs from "fs";
9
- import { spawn } from "child_process";
10
- import open from "open";
11
- import { createRequire } from "module";
12
-
13
- const _require = createRequire(import.meta.url);
14
- const __dirname = path.dirname(fileURLToPath(import.meta.url));
15
- const _pkg = JSON.parse(fs.readFileSync(path.join(__dirname, "../package.json"), "utf8"));
16
-
18
+ // ─────────────────────────────────────────────────────────────────
19
+ // claudeboard init
20
+ // ─────────────────────────────────────────────────────────────────
21
+ function runInit() {
22
+ header('init');
23
+
24
+ const cwd = process.cwd();
25
+ const boardDir = path.join(cwd, '.claudeboard');
26
+ const projectName = path.basename(cwd);
27
+
28
+ console.log(chalk.dim('Directorio: ') + chalk.cyan(cwd));
29
+ console.log('');
30
+
31
+ // 1. Create .claudeboard/
32
+ if (!fs.existsSync(boardDir)) {
33
+ fs.mkdirSync(boardDir, { recursive: true });
34
+ console.log(chalk.green('✔') + ' Carpeta .claudeboard/ creada');
35
+ } else {
36
+ console.log(chalk.yellow('~') + ' .claudeboard/ ya existe — no se sobreescribe');
37
+ }
17
38
 
18
- const LOGO = `
19
- ${chalk.cyan("╔════════════════════════════════════════════╗")}
20
- ${chalk.cyan("║")} ${chalk.bold.white("●")} ${chalk.bold.cyan("CLAUDEBOARD")} ${chalk.dim("powered by High Value, LLC")} ${chalk.cyan("║")}
21
- ${chalk.cyan("╚════════════════════════════════════════════╝")}
22
- `;
39
+ // 2. Write config.json only if missing
40
+ const configPath = path.join(boardDir, 'config.json');
41
+ if (!fs.existsSync(configPath)) {
42
+ fs.writeFileSync(configPath, JSON.stringify({ projectName, createdAt: new Date().toISOString() }, null, 2));
43
+ console.log(chalk.green('✔') + ' config.json inicializado');
44
+ }
23
45
 
24
- function loadConfig() {
46
+ // 3. Update .gitignore
47
+ const gitignorePath = path.join(cwd, '.gitignore');
48
+ const ignoreEntry = '.claudeboard/';
49
+ let gitignored = false;
25
50
  try {
26
- const config = JSON.parse(fs.readFileSync(path.join(process.cwd(), ".claudeboard.json"), "utf8"));
27
- // Inject API key into environment automatically
28
- if (config.anthropicKey) {
29
- process.env.ANTHROPIC_API_KEY = config.anthropicKey;
30
- }
31
- if (!process.env.ANTHROPIC_API_KEY) {
32
- console.log(chalk.yellow("⚠️ ANTHROPIC_API_KEY not found."));
33
- console.log(chalk.dim(" Run claudeboard init again, or: export ANTHROPIC_API_KEY=sk-ant-..."));
34
- process.exit(1);
51
+ if (fs.existsSync(gitignorePath)) {
52
+ const content = fs.readFileSync(gitignorePath, 'utf-8');
53
+ if (!content.includes(ignoreEntry)) {
54
+ fs.appendFileSync(gitignorePath, `\n# ClaudeBoard — datos del board (tareas, historial, handoffs)\n${ignoreEntry}\n`);
55
+ gitignored = true;
56
+ }
57
+ } else {
58
+ fs.writeFileSync(gitignorePath, `# ClaudeBoard — datos del board (tareas, historial, handoffs)\n${ignoreEntry}\n`);
59
+ gitignored = true;
35
60
  }
36
- return config;
37
- } catch {
38
- console.log(chalk.yellow("No .claudeboard.json found. Run: claudeboard init"));
39
- process.exit(1);
61
+ if (gitignored) console.log(chalk.green('✔') + ' .claudeboard/ agregado al .gitignore');
62
+ else console.log(chalk.yellow('~') + ' .gitignore ya incluye .claudeboard/');
63
+ } catch { /* non-fatal */ }
64
+
65
+ // 4. Create a starter context.md if missing
66
+ const contextPath = path.join(boardDir, 'context.md');
67
+ if (!fs.existsSync(contextPath)) {
68
+ fs.writeFileSync(contextPath, `# Guías de marca / contexto de "${projectName}"\n\n<!-- Opcional: agregá colores, tipografías, tono de voz, reglas del proyecto. -->\n<!-- Los agentes lo leerán antes de trabajar. -->\n`);
69
+ console.log(chalk.green('✔') + ' .claudeboard/context.md creado (editalo con tus guías de marca)');
40
70
  }
41
- }
42
-
43
- // ─── INIT ────────────────────────────────────────────────────────────────────
44
- program
45
- .command("init")
46
- .description("Initialize claudeboard in a project")
47
- .action(async () => {
48
- console.log(LOGO);
49
- const { default: Enquirer } = await import("enquirer");
50
- const enquirer = new Enquirer();
51
- console.log(chalk.bold("Let's set up your AI engineering team — powered by High Value, LLC.\n"));
52
-
53
- const answers = await enquirer.prompt([
54
- { type: "input", name: "projectName", message: "Project name:", initial: path.basename(process.cwd()) },
55
- { type: "input", name: "supabaseUrl", message: "Supabase URL:", hint: "https://xxxx.supabase.co" },
56
- { type: "input", name: "supabaseKey", message: "Supabase anon key:" },
57
- { type: "password", name: "anthropicKey", message: "Anthropic API key:", hint: "sk-ant-..." },
58
- { type: "input", name: "port", message: "Dashboard port:", initial: "3131" },
59
- ]);
60
-
61
- const spinner = ora("Creating config...").start();
62
-
63
- const config = {
64
- projectName: answers.projectName,
65
- port: parseInt(answers.port),
66
- supabaseUrl: answers.supabaseUrl,
67
- supabaseKey: answers.supabaseKey,
68
- anthropicKey: answers.anthropicKey,
69
- projectDir: process.cwd(),
70
- createdAt: new Date().toISOString(),
71
- };
72
-
73
- fs.writeFileSync(path.join(process.cwd(), ".claudeboard.json"), JSON.stringify(config, null, 2));
74
-
75
- const sqlSrc = path.join(__dirname, "../sql/setup.sql");
76
- fs.copyFileSync(sqlSrc, path.join(process.cwd(), "claudeboard-setup.sql"));
77
-
78
- spinner.succeed(chalk.green("Config created!"));
79
-
80
- console.log(`
81
- ${chalk.bold("Next steps:")}
82
-
83
- ${chalk.cyan("1.")} Run the SQL in your Supabase SQL Editor:
84
- ${chalk.dim("→ claudeboard-setup.sql")}
85
-
86
- ${chalk.cyan("2.")} Start the dashboard:
87
- ${chalk.bold("claudeboard start")}
88
-
89
- ${chalk.cyan("3.")} Run the AI team with your PRD:
90
- ${chalk.bold("claudeboard run --prd ./PRD.md --project ./your-app")}
91
- `);
92
- });
93
71
 
94
- // ─── START DASHBOARD ─────────────────────────────────────────────────────────
95
- program
96
- .command("start")
97
- .description("Start the dashboard server")
98
- .option("-p, --port <port>", "Port number")
99
- .action(async (opts) => {
100
- console.log(LOGO);
101
- const config = loadConfig();
102
- const port = opts.port || config.port || 3131;
103
- const spinner = ora("Starting dashboard...").start();
104
-
105
- const serverPath = path.join(__dirname, "../dashboard/server.js");
106
- const server = spawn("node", [serverPath], {
107
- env: {
108
- ...process.env,
109
- SUPABASE_URL: config.supabaseUrl,
110
- SUPABASE_KEY: config.supabaseKey,
111
- ANTHROPIC_API_KEY: config.anthropicKey || process.env.ANTHROPIC_API_KEY || "",
112
- PORT: String(port),
113
- PROJECT_NAME: config.projectName,
114
- PROJECT_DIR: config.projectDir || process.cwd(),
115
- },
116
- stdio: "pipe",
117
- });
118
-
119
- server.stdout.on("data", (data) => {
120
- if (data.toString().includes("READY")) {
121
- spinner.succeed(chalk.green("Dashboard running!"));
122
- console.log(`\n ${chalk.bold("→")} ${chalk.cyan(`http://localhost:${port}`)}\n`);
123
- console.log(chalk.dim(" Press Ctrl+C to stop\n"));
124
- open(`http://localhost:${port}`);
125
- }
126
- });
127
-
128
- server.stderr.on("data", (d) => console.error(chalk.red(d.toString())));
129
- process.on("SIGINT", () => { server.kill(); process.exit(0); });
130
- });
72
+ console.log('');
73
+ console.log(chalk.bold('¡Listo! ') + chalk.dim('Corré ') + chalk.cyan('claudeboard') + chalk.dim(' para iniciar el board en este proyecto.'));
74
+ console.log('');
75
+ }
131
76
 
132
- // ─── RUN AI TEAM ─────────────────────────────────────────────────────────────
133
- program
134
- .command("run")
135
- .description("Run the AI engineering team on your project")
136
- .requiredOption("--prd <path>", "Path to PRD markdown file")
137
- .requiredOption("--project <path>", "Path to your app project directory")
138
- .option("--restart", "Force restart from scratch (ignore existing tasks in board)")
139
- .option("--expo-port <port>", "Expo Web port for QA screenshots", "8081")
140
- .option("--ios", "Use iOS Simulator instead of Expo Web for QA (requires Xcode)")
141
- .action(async (opts) => {
142
- console.log(LOGO);
143
- const config = loadConfig();
144
-
145
- if (!fs.existsSync(opts.prd)) {
146
- console.log(chalk.red(`PRD not found: ${opts.prd}`)); process.exit(1);
147
- }
148
- if (!fs.existsSync(opts.project)) {
149
- console.log(chalk.red(`Project not found: ${opts.project}`)); process.exit(1);
150
- }
77
+ // ─────────────────────────────────────────────────────────────────
78
+ // Team selection prompt
79
+ // ─────────────────────────────────────────────────────────────────
80
+ const TEAMS = [
81
+ { label: '🧑‍💻 Solo Dev ', desc: '1 agente, enfocado, bajo costo de tokens', maxAgents: 1 },
82
+ { label: '👥 Small Team ', desc: '3 agentes (Lead + 2 especialistas)', maxAgents: 3 },
83
+ { label: '🚀 Full Team ', desc: '6 agentes (Lead + 5 especialistas)', maxAgents: 6 },
84
+ { label: '🏭 Enterprise ', desc: '9 agentes (Lead + 8 especialistas, máx paralelismo)', maxAgents: 9 },
85
+ ];
86
+
87
+ function drawMenu(teams, selected, lineCount) {
88
+ const lines = [chalk.bold('? ') + 'Seleccioná tu equipo de agentes:'];
89
+ for (let i = 0; i < teams.length; i++) {
90
+ const t = teams[i];
91
+ const cursor = i === selected ? chalk.cyan('❯') : ' ';
92
+ const label = i === selected ? chalk.bold(t.label) : chalk.dim(t.label);
93
+ lines.push(` ${cursor} ${label} ${chalk.dim(t.desc)}`);
94
+ }
95
+ if (lineCount > 0) process.stdout.write(`\x1b[${lineCount}A\x1b[0J`);
96
+ process.stdout.write(lines.join('\n') + '\n');
97
+ return lines.length;
98
+ }
151
99
 
152
- console.log(chalk.bold(` AI Team starting for: ${chalk.cyan(config.projectName)}\n`));
153
- console.log(chalk.dim(` Dashboard http://localhost:${config.port}`));
154
- console.log(chalk.dim(` PRD → ${opts.prd}`));
155
- console.log(chalk.dim(` Project → ${opts.project}`));
156
- if (opts.restart) console.log(chalk.yellow(` Mode → FORCE RESTART\n`));
157
- else console.log(chalk.dim(` Mode → auto-resume if tasks exist\n`));
158
-
159
- // ── Verify Claude Code CLI is installed ───────────────────────────────────
160
- const { execSync } = await import("child_process");
161
- const { resolveClaudePath, installHint } = await import("../agents/claude-resolver.js");
162
- const claudePath = resolveClaudePath();
163
- if (!claudePath) {
164
- console.log(chalk.red("\n ✗ Claude Code CLI not found!\n"));
165
- for (const line of installHint().split("\n")) {
166
- console.log(chalk.yellow(` ${line}`));
100
+ function promptTeamSelection(skipMaxAgents) {
101
+ if (skipMaxAgents !== undefined || !process.stdin.isTTY) return Promise.resolve(null);
102
+
103
+ return new Promise((resolve) => {
104
+ let selected = 0;
105
+ let lineCount = drawMenu(TEAMS, selected, 0);
106
+
107
+ process.stdin.setRawMode(true);
108
+ process.stdin.resume();
109
+ process.stdin.setEncoding('utf8');
110
+
111
+ function onKey(key) {
112
+ if (key === '\x1b[A') { selected = Math.max(0, selected - 1); lineCount = drawMenu(TEAMS, selected, lineCount); }
113
+ else if (key === '\x1b[B') { selected = Math.min(TEAMS.length - 1, selected + 1); lineCount = drawMenu(TEAMS, selected, lineCount); }
114
+ else if (key === '\r' || key === '\n') {
115
+ process.stdin.removeListener('data', onKey);
116
+ process.stdin.setRawMode(false);
117
+ process.stdin.pause();
118
+ process.stdout.write(`\x1b[${lineCount}A\x1b[0J`);
119
+ const team = TEAMS[selected];
120
+ process.stdout.write(chalk.bold('✔ ') + 'Equipo: ' + chalk.cyan(team.label.trim()) + chalk.dim(' — ' + team.desc) + '\n');
121
+ resolve(team);
122
+ } else if (key === '\x03') {
123
+ process.stdin.setRawMode(false);
124
+ process.exit(0);
167
125
  }
168
- console.log();
169
- process.exit(1);
170
126
  }
171
- try {
172
- const version = execSync(`"${claudePath}" --version`, { stdio: "pipe" }).toString().trim();
173
- console.log(chalk.dim(` Claude Code → ${version} (${claudePath})\n`));
174
- } catch {
175
- console.log(chalk.dim(` Claude Code → ${claudePath}\n`));
176
- }
177
-
178
- const resolvedProject = path.resolve(opts.project);
179
-
180
- // Persist the project path so `claudeboard start` uses the right directory for Expo
181
- const configPath = path.join(process.cwd(), ".claudeboard.json");
182
- try {
183
- const saved = JSON.parse(fs.readFileSync(configPath, "utf8"));
184
- saved.projectDir = resolvedProject;
185
- fs.writeFileSync(configPath, JSON.stringify(saved, null, 2));
186
- } catch {}
187
-
188
- const { runOrchestrator } = await import("../agents/orchestrator.js");
189
-
190
- await runOrchestrator({
191
- prdPath: path.resolve(opts.prd),
192
- projectPath: resolvedProject,
193
- supabaseUrl: config.supabaseUrl,
194
- supabaseKey: config.supabaseKey,
195
- projectName: config.projectName,
196
- expoPort: parseInt(opts.expoPort),
197
- forceRestart: !!opts.restart,
198
- useIOS: !!opts.ios,
199
- });
127
+ process.stdin.on('data', onKey);
200
128
  });
129
+ }
201
130
 
202
- // ─── IMPORT PRD ──────────────────────────────────────────────────────────────
203
- program
204
- .command("import-prd <file>")
205
- .description("Parse PRD → create tasks in board (no agents run)")
206
- .action(async (file) => {
207
- console.log(LOGO);
208
- const config = loadConfig();
131
+ // ─────────────────────────────────────────────────────────────────
132
+ // claudeboard start (default when no subcommand)
133
+ // ─────────────────────────────────────────────────────────────────
134
+ async function runStart(rawArgs) {
135
+ // Parse simple flags: --port, --open, --webhook, --max-agents
136
+ const args = rawArgs || [];
137
+ const getFlag = (name, shortName, def) => {
138
+ const longIdx = args.indexOf(`--${name}`);
139
+ const shortIdx = shortName ? args.indexOf(`-${shortName}`) : -1;
140
+ const idx = longIdx !== -1 ? longIdx : shortIdx;
141
+ if (idx !== -1 && args[idx + 1] !== undefined) return args[idx + 1];
142
+ // --name=value form
143
+ const pair = args.find(a => a.startsWith(`--${name}=`));
144
+ if (pair) return pair.split('=')[1];
145
+ return def;
146
+ };
147
+ const flagExists = (name) => args.includes(`--${name}`);
148
+
149
+ const port = parseInt(getFlag('port', 'p', '3000'), 10) || 3000;
150
+ const openBrowser = getFlag('open', null, 'true') !== 'false';
151
+ const webhook = getFlag('webhook', null, null);
152
+ const maxAgentsRaw = getFlag('max-agents', null, undefined);
153
+
154
+ // ── Auto-init if .claudeboard/ doesn't exist ──────────────────
155
+ const cwd = process.cwd();
156
+ const boardDir = path.join(cwd, '.claudeboard');
157
+ if (!fs.existsSync(boardDir)) {
158
+ console.log(chalk.dim('No se encontró .claudeboard/ — inicializando automáticamente…'));
159
+ console.log('');
160
+ runInit();
161
+ }
209
162
 
210
- if (!fs.existsSync(file)) {
211
- console.log(chalk.red(`File not found: ${file}`)); process.exit(1);
212
- }
163
+ header();
164
+ console.log(chalk.dim('Proyecto: ') + chalk.cyan(path.basename(cwd)) + chalk.dim(' (' + cwd + ')'));
165
+ console.log('');
213
166
 
214
- const prdContent = fs.readFileSync(file, "utf8");
215
- const { initBoard } = await import("../agents/board-client.js");
216
- const { runArchitectAgent } = await import("../agents/architect.js");
167
+ const team = await promptTeamSelection(maxAgentsRaw);
168
+ const maxAgents = maxAgentsRaw !== undefined
169
+ ? (parseInt(maxAgentsRaw, 10) || 1)
170
+ : (team ? team.maxAgents : 1);
217
171
 
218
- initBoard(config.supabaseUrl, config.supabaseKey, config.projectName);
219
- const result = await runArchitectAgent(prdContent, config.projectName);
172
+ // Store minimal config (no projectPath — it's always process.cwd())
173
+ const { setConfig } = require(path.join(__dirname, '..', 'src', 'store'));
174
+ if (webhook) setConfig({ webhook });
220
175
 
221
- console.log(chalk.green(`\n ✓ Created ${result.totalTasks} tasks across ${result.epics.length} epics`));
222
- console.log(`\n Run ${chalk.bold("claudeboard start")} to see your board.\n`);
223
- });
176
+ console.log('');
177
+ console.log(chalk.dim(`Iniciando en puerto ${port}…`));
178
+ console.log('');
224
179
 
225
- // ─── STATUS ──────────────────────────────────────────────────────────────────
226
- program
227
- .command("status")
228
- .description("Show current board status in terminal")
229
- .action(async () => {
230
- const config = loadConfig();
231
- const { initBoard, getStats } = await import("../agents/board-client.js");
232
- initBoard(config.supabaseUrl, config.supabaseKey, config.projectName);
233
-
234
- const stats = await getStats();
235
- const bar = "█".repeat(Math.floor(stats.pct / 5)) + "░".repeat(20 - Math.floor(stats.pct / 5));
236
-
237
- console.log(LOGO);
238
- console.log(chalk.bold(` ${config.projectName}\n`));
239
- console.log(` [${chalk.green(bar)}] ${chalk.bold(stats.pct + "%")}`);
240
- console.log(`\n ${chalk.green("✓ Done:")} ${stats.done}`);
241
- console.log(` ${chalk.yellow("◌ Running:")} ${stats.in_progress}`);
242
- console.log(` ${chalk.dim("○ Todo:")} ${stats.todo}`);
243
- console.log(` ${chalk.red("✗ Error:")} ${stats.error}\n`);
244
- });
180
+ const { createServer } = require(path.join(__dirname, '..', 'src', 'server'));
181
+ createServer({ port, maxAgents, webhook, openBrowser });
245
182
 
246
- program
247
- .name("claudeboard")
248
- .description("AI engineering team — from PRD to working app, autonomously — powered by High Value, LLC")
249
- .version(_pkg.version);
183
+ console.log(chalk.dim('Ctrl+C para detener'));
184
+ }
250
185
 
251
- program.parse();
186
+ // ─────────────────────────────────────────────────────────────────
187
+ // Entry point — dispatch subcommand
188
+ // ─────────────────────────────────────────────────────────────────
189
+ const args = process.argv.slice(2);
190
+ const subcommand = args[0];
191
+
192
+ if (subcommand === '--version' || subcommand === '-v') {
193
+ console.log(PKG_VERSION);
194
+ } else if (subcommand === '--help' || subcommand === '-h') {
195
+ console.log(chalk.bold.hex('#e3c69a')('ClaudeBoard v3 ✦') + chalk.dim(' v' + PKG_VERSION));
196
+ console.log('');
197
+ console.log(chalk.bold('Uso:'));
198
+ console.log(' claudeboard init Inicializa .claudeboard/ en el proyecto actual');
199
+ console.log(' claudeboard Inicia el board (en el directorio actual)');
200
+ console.log('');
201
+ console.log(chalk.bold('Opciones de start:'));
202
+ console.log(' -p, --port <n> Puerto (default: 3000)');
203
+ console.log(' --max-agents <n> Cantidad de agentes paralelos (evita el prompt)');
204
+ console.log(' --open false No abrir el browser automáticamente');
205
+ console.log(' --webhook <url> URL de webhook para notificaciones');
206
+ console.log('');
207
+ console.log(chalk.bold('Ejemplo — múltiples proyectos en simultáneo:'));
208
+ console.log(chalk.dim(' cd ~/projects/app-a && claudeboard --port 3000'));
209
+ console.log(chalk.dim(' cd ~/projects/app-b && claudeboard --port 3001'));
210
+ } else if (subcommand === 'init') {
211
+ runInit();
212
+ } else if (!subcommand || subcommand === 'start' || subcommand.startsWith('-')) {
213
+ // No subcommand or "start" or flags → default to start
214
+ runStart(args.filter(a => a !== 'start'));
215
+ } else {
216
+ console.log(chalk.red(`Subcomando desconocido: "${subcommand}"`));
217
+ console.log(chalk.dim('Corré `claudeboard --help` para ver los comandos disponibles.'));
218
+ process.exit(1);
219
+ }
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env node
2
+ // bin/init-context.js — copies context template to .claudeboard/context.md in the current project
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+
6
+ const targetDir = path.join(process.cwd(), '.claudeboard');
7
+ const targetFile = path.join(targetDir, 'context.md');
8
+ const templateFile = path.join(__dirname, '..', 'src', 'context-template.md');
9
+
10
+ if (!fs.existsSync(targetDir)) {
11
+ fs.mkdirSync(targetDir, { recursive: true });
12
+ }
13
+
14
+ if (fs.existsSync(targetFile)) {
15
+ console.log(`Already exists: ${targetFile}`);
16
+ console.log('Edit it directly to customize your project context.');
17
+ process.exit(0);
18
+ }
19
+
20
+ fs.copyFileSync(templateFile, targetFile);
21
+ console.log(`Created: ${targetFile}`);
22
+ console.log('Edit .claudeboard/context.md to add your project brand guidelines and design tokens.');
package/package.json CHANGED
@@ -1,57 +1,36 @@
1
1
  {
2
2
  "name": "claudeboard",
3
- "version": "2.15.4",
4
- "description": "AI engineering team from PRD to working mobile app, autonomously",
5
- "type": "module",
3
+ "version": "3.1.0",
4
+ "description": "Visual orchestrator for Claude Code agent teams",
6
5
  "bin": {
7
- "claudeboard": "./bin/cli.js"
6
+ "claudeboard": "bin/cli.js"
8
7
  },
9
8
  "files": [
10
9
  "bin/",
11
- "dashboard/",
12
- "agents/",
13
- "tools/",
14
- "sql/",
10
+ "src/",
11
+ "public/",
15
12
  "README.md"
16
13
  ],
17
- "dependencies": {
18
- "@anthropic-ai/claude-agent-sdk": "latest",
19
- "@supabase/supabase-js": "^2.43.1",
20
- "chalk": "^5.3.0",
21
- "commander": "^12.0.0",
22
- "cors": "^2.8.5",
23
- "dotenv": "^16.4.5",
24
- "enquirer": "^2.4.1",
25
- "express": "^4.18.3",
26
- "node-pty": "^1.0.0",
27
- "open": "^10.1.0",
28
- "ora": "^8.0.1",
29
- "puppeteer": "^22.8.0",
30
- "ws": "^8.17.0"
31
- },
32
- "engines": {
33
- "node": ">=18.0.0"
34
- },
35
- "publishConfig": {
36
- "access": "public"
14
+ "scripts": {
15
+ "start": "node bin/cli.js"
37
16
  },
38
- "repository": {
39
- "type": "git",
40
- "url": "https://github.com/highvaluedigital/claudeboard"
41
- },
42
- "author": "highvaluedigital",
43
- "license": "MIT",
44
17
  "keywords": [
45
18
  "claude",
46
19
  "ai",
47
- "agent",
48
- "coding",
49
- "automation",
20
+ "orchestrator",
21
+ "agents",
50
22
  "dashboard",
51
- "mobile",
52
- "expo",
53
- "react-native",
54
- "prd",
55
- "engineering"
56
- ]
23
+ "kanban"
24
+ ],
25
+ "license": "MIT",
26
+ "engines": {
27
+ "node": ">=18"
28
+ },
29
+ "dependencies": {
30
+ "chalk": "^4.1.2",
31
+ "commander": "^12.0.0",
32
+ "express": "^4.18.2",
33
+ "open": "^10.1.0",
34
+ "ws": "^8.16.0"
35
+ }
57
36
  }