brain-dev 0.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.
Files changed (78) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +152 -0
  3. package/agents/brain-checker.md +33 -0
  4. package/agents/brain-debugger.md +35 -0
  5. package/agents/brain-executor.md +37 -0
  6. package/agents/brain-mapper.md +44 -0
  7. package/agents/brain-planner.md +49 -0
  8. package/agents/brain-researcher.md +47 -0
  9. package/agents/brain-synthesizer.md +43 -0
  10. package/agents/brain-verifier.md +41 -0
  11. package/bin/brain-tools.cjs +185 -0
  12. package/bin/lib/adr.cjs +283 -0
  13. package/bin/lib/agents.cjs +152 -0
  14. package/bin/lib/anti-patterns.cjs +183 -0
  15. package/bin/lib/audit.cjs +268 -0
  16. package/bin/lib/commands/adr.cjs +126 -0
  17. package/bin/lib/commands/complete.cjs +270 -0
  18. package/bin/lib/commands/config.cjs +306 -0
  19. package/bin/lib/commands/discuss.cjs +237 -0
  20. package/bin/lib/commands/execute.cjs +415 -0
  21. package/bin/lib/commands/health.cjs +103 -0
  22. package/bin/lib/commands/map.cjs +101 -0
  23. package/bin/lib/commands/new-project.cjs +885 -0
  24. package/bin/lib/commands/pause.cjs +142 -0
  25. package/bin/lib/commands/phase-manage.cjs +357 -0
  26. package/bin/lib/commands/plan.cjs +451 -0
  27. package/bin/lib/commands/progress.cjs +167 -0
  28. package/bin/lib/commands/quick.cjs +447 -0
  29. package/bin/lib/commands/resume.cjs +196 -0
  30. package/bin/lib/commands/storm.cjs +590 -0
  31. package/bin/lib/commands/verify.cjs +504 -0
  32. package/bin/lib/commands.cjs +263 -0
  33. package/bin/lib/complexity.cjs +138 -0
  34. package/bin/lib/complexity.test.cjs +108 -0
  35. package/bin/lib/config.cjs +452 -0
  36. package/bin/lib/core.cjs +62 -0
  37. package/bin/lib/detect.cjs +603 -0
  38. package/bin/lib/git.cjs +112 -0
  39. package/bin/lib/health.cjs +356 -0
  40. package/bin/lib/init.cjs +310 -0
  41. package/bin/lib/logger.cjs +100 -0
  42. package/bin/lib/platform.cjs +58 -0
  43. package/bin/lib/requirements.cjs +158 -0
  44. package/bin/lib/roadmap.cjs +228 -0
  45. package/bin/lib/security.cjs +237 -0
  46. package/bin/lib/state.cjs +353 -0
  47. package/bin/lib/templates.cjs +48 -0
  48. package/bin/templates/advocate.md +182 -0
  49. package/bin/templates/checkpoint.md +55 -0
  50. package/bin/templates/debugger.md +148 -0
  51. package/bin/templates/discuss.md +60 -0
  52. package/bin/templates/executor.md +201 -0
  53. package/bin/templates/mapper.md +129 -0
  54. package/bin/templates/plan-checker.md +134 -0
  55. package/bin/templates/planner.md +165 -0
  56. package/bin/templates/researcher.md +78 -0
  57. package/bin/templates/storm.html +376 -0
  58. package/bin/templates/synthesis.md +30 -0
  59. package/bin/templates/verifier.md +181 -0
  60. package/commands/brain/adr.md +34 -0
  61. package/commands/brain/complete.md +37 -0
  62. package/commands/brain/config.md +37 -0
  63. package/commands/brain/discuss.md +35 -0
  64. package/commands/brain/execute.md +38 -0
  65. package/commands/brain/health.md +33 -0
  66. package/commands/brain/map.md +35 -0
  67. package/commands/brain/new-project.md +38 -0
  68. package/commands/brain/pause.md +26 -0
  69. package/commands/brain/plan.md +38 -0
  70. package/commands/brain/progress.md +28 -0
  71. package/commands/brain/quick.md +51 -0
  72. package/commands/brain/resume.md +28 -0
  73. package/commands/brain/storm.md +30 -0
  74. package/commands/brain/verify.md +39 -0
  75. package/hooks/bootstrap.sh +54 -0
  76. package/hooks/post-tool-use.sh +45 -0
  77. package/hooks/statusline.sh +130 -0
  78. package/package.json +36 -0
@@ -0,0 +1,263 @@
1
+ 'use strict';
2
+
3
+ const path = require('node:path');
4
+
5
+ /**
6
+ * Command registry for all brain-dev CLI commands.
7
+ * Each entry defines name, description, usage, group, implemented status,
8
+ * whether it needs .brain/ state, and optional args documentation.
9
+ */
10
+ const COMMANDS = [
11
+ // Setup
12
+ {
13
+ name: 'init',
14
+ description: 'Initialize brain in current project',
15
+ usage: 'brain-dev init [--force]',
16
+ group: 'Setup',
17
+ implemented: true,
18
+ needsState: false,
19
+ args: ' --force Wipe and recreate existing .brain/ directory'
20
+ },
21
+ {
22
+ name: 'new-project',
23
+ description: 'Start a new project with guided questioning',
24
+ usage: 'brain-dev new-project [--answers <json>] [--synthesize] [--generate-roadmap] [--finalize]',
25
+ group: 'Setup',
26
+ implemented: true,
27
+ needsState: true,
28
+ args: ' --answers <json> Provide user answers as JSON\n --synthesize Spawn synthesis agent\n --generate-roadmap Generate REQUIREMENTS.md and ROADMAP.md\n --finalize Finalize project setup\n --project-name <name> Project name (used with --finalize)'
29
+ },
30
+ {
31
+ name: 'help',
32
+ description: 'Show all available commands',
33
+ usage: 'brain-dev help [command]',
34
+ group: 'Setup',
35
+ implemented: true,
36
+ needsState: false,
37
+ args: ' [command] Show detailed help for a specific command'
38
+ },
39
+
40
+ // Lifecycle
41
+ {
42
+ name: 'discuss',
43
+ description: 'Capture decisions before planning',
44
+ usage: 'brain-dev discuss [--phase <n>] [--save --decisions <json>]',
45
+ group: 'Lifecycle',
46
+ implemented: true,
47
+ needsState: true,
48
+ args: ' --phase <n> Target phase to discuss (default: current)\n --save Save decisions to CONTEXT.md\n --decisions <json> Decisions JSON (used with --save)'
49
+ },
50
+ {
51
+ name: 'plan',
52
+ description: 'Create execution plans',
53
+ usage: 'brain-dev plan [--phase <n>] [--all]',
54
+ group: 'Lifecycle',
55
+ implemented: true,
56
+ needsState: true,
57
+ args: ' --phase <n> Target phase number to plan\n --all Plan all unplanned phases sequentially'
58
+ },
59
+ {
60
+ name: 'quick',
61
+ description: 'Quick task without full phase ceremony',
62
+ usage: 'brain-dev quick [--full] <description>',
63
+ group: 'Lifecycle',
64
+ implemented: true,
65
+ needsState: true,
66
+ args: ' --full Enable plan checking + verification\n --execute --task N Execute task N\n --verify --task N Verify task N (--full only)\n --complete --task N Complete and commit task N'
67
+ },
68
+ {
69
+ name: 'execute',
70
+ description: 'Execute plans with verification',
71
+ usage: 'brain-dev execute [--plan <id>]',
72
+ group: 'Lifecycle',
73
+ implemented: true,
74
+ needsState: true,
75
+ args: ' --plan <id> Specific plan to execute (e.g. 01-02)'
76
+ },
77
+ {
78
+ name: 'verify',
79
+ description: 'Run verification checks on completed work',
80
+ usage: 'brain-dev verify [--phase <n>]',
81
+ group: 'Lifecycle',
82
+ implemented: true,
83
+ needsState: true,
84
+ args: ' --phase <n> Phase to verify'
85
+ },
86
+ {
87
+ name: 'complete',
88
+ description: 'Mark phase or milestone as complete',
89
+ usage: 'brain-dev complete [--phase <n>]',
90
+ group: 'Lifecycle',
91
+ implemented: true,
92
+ needsState: true,
93
+ args: ' --phase <n> Phase to mark complete'
94
+ },
95
+ {
96
+ name: 'map',
97
+ description: 'Map codebase structure and patterns',
98
+ usage: 'brain-dev map [--focus tech|arch|quality|concerns]',
99
+ group: 'Lifecycle',
100
+ implemented: true,
101
+ needsState: true,
102
+ args: ' --focus <area> Focus on specific area: tech, arch, quality, or concerns'
103
+ },
104
+ {
105
+ name: 'phase',
106
+ description: 'Manage project phases (add, remove, reorder)',
107
+ usage: 'brain-dev phase <add|insert|remove|reorder|list>',
108
+ group: 'Lifecycle',
109
+ implemented: true,
110
+ needsState: true,
111
+ args: ' add Add a new phase\n insert Insert decimal phase (e.g. 2.1)\n remove Remove a phase\n reorder Reorder phases\n list Show all phases (default)'
112
+ },
113
+
114
+ // Session
115
+ {
116
+ name: 'status',
117
+ description: 'Show project state (used by SessionStart hook)',
118
+ usage: 'brain-dev status [--json]',
119
+ group: 'Session',
120
+ implemented: true,
121
+ needsState: true,
122
+ args: ' --json Output raw JSON (for hooks and piping)'
123
+ },
124
+ {
125
+ name: 'progress',
126
+ description: 'Show current progress and status',
127
+ usage: 'brain-dev progress [--verbose]',
128
+ group: 'Session',
129
+ implemented: true,
130
+ needsState: true,
131
+ args: ' --verbose Show full dashboard with all phases'
132
+ },
133
+ {
134
+ name: 'pause',
135
+ description: 'Save session state for later resumption',
136
+ usage: 'brain-dev pause [--note <msg>]',
137
+ group: 'Session',
138
+ implemented: true,
139
+ needsState: true,
140
+ args: ' --note <msg> Add a note about where you stopped'
141
+ },
142
+ {
143
+ name: 'resume',
144
+ description: 'Resume from last saved session state',
145
+ usage: 'brain-dev resume [--session <id>]',
146
+ group: 'Session',
147
+ implemented: true,
148
+ needsState: true,
149
+ args: ' --session <id> Resume a specific session by timestamp ID'
150
+ },
151
+ // Tools
152
+ {
153
+ name: 'storm',
154
+ description: 'Launch visual brainstorming server',
155
+ usage: 'brain-dev storm <topic> [--stop] [--port <n>] [--finalize]',
156
+ group: 'Tools',
157
+ implemented: true,
158
+ needsState: true,
159
+ args: ' <topic> Topic to brainstorm\n --stop Stop running server\n --port <n> Custom port number\n --finalize Generate output.md from fragments'
160
+ },
161
+ {
162
+ name: 'adr',
163
+ description: 'Manage architecture decision records',
164
+ usage: 'brain-dev adr <create|list|search> [options]',
165
+ group: 'Tools',
166
+ implemented: true,
167
+ needsState: true,
168
+ args: ' create Create new ADR interactively\n list [--phase <n>] List ADRs (optionally filtered by phase)\n search <term> Search ADR content'
169
+ },
170
+
171
+ // Config
172
+ {
173
+ name: 'config',
174
+ description: 'Manage brain configuration',
175
+ usage: 'brain-dev config [set|get|list|reset|docs|export|import] [args] [--global]',
176
+ group: 'Config',
177
+ implemented: true,
178
+ needsState: true,
179
+ args: ' set <key> <value> Set a configuration value\n get <key> Get a configuration value\n list [--category X] List all settings grouped by category\n reset [key|category] Reset to defaults\n docs Show full schema reference\n export Export config as portable JSON\n import <file.json> Import config from file\n --global Target ~/.brain/defaults.json'
180
+ },
181
+
182
+ // Meta
183
+ {
184
+ name: 'health',
185
+ description: 'Run health diagnostics and auto-repair safe issues',
186
+ usage: 'brain-dev health [--fix] [--quick] [--json]',
187
+ group: 'Meta',
188
+ implemented: true,
189
+ needsState: false,
190
+ args: ' --fix Enable aggressive repair of hooks and templates\n --quick Run safe checks only (used by bootstrap)\n --json Force JSON output'
191
+ },
192
+ {
193
+ name: 'version',
194
+ description: 'Show brain-dev version',
195
+ usage: 'brain-dev version',
196
+ group: 'Meta',
197
+ implemented: true,
198
+ needsState: false,
199
+ args: ''
200
+ }
201
+ ];
202
+
203
+ /**
204
+ * Group order for display purposes.
205
+ */
206
+ const GROUP_ORDER = ['Setup', 'Lifecycle', 'Session', 'Tools', 'Config', 'Meta'];
207
+
208
+ /**
209
+ * Get formatted help text for a single command.
210
+ * @param {string} name - Command name
211
+ * @returns {string|null} Formatted help text, or null if command not found
212
+ */
213
+ function getCommandHelp(name) {
214
+ const cmd = COMMANDS.find(c => c.name === name);
215
+ if (!cmd) return null;
216
+
217
+ let text = `${cmd.name} -- ${cmd.description}\n\nUsage: ${cmd.usage}`;
218
+ if (cmd.args) {
219
+ text += `\n\nArguments:\n${cmd.args}`;
220
+ }
221
+ return text;
222
+ }
223
+
224
+ /**
225
+ * Generate full help text with commands grouped by lifecycle stage.
226
+ * @returns {string} Formatted help text
227
+ */
228
+ function showHelp() {
229
+ const pkg = require(path.join(__dirname, '..', '..', 'package.json'));
230
+ const lines = [`[brain] v${pkg.version} - AI development workflow orchestrator`, ''];
231
+
232
+ for (const group of GROUP_ORDER) {
233
+ const cmds = COMMANDS.filter(c => c.group === group);
234
+ lines.push(`${group}:`);
235
+ for (const cmd of cmds) {
236
+ const padded = cmd.name.padEnd(14);
237
+ lines.push(` ${padded}${cmd.description}`);
238
+ }
239
+ lines.push('');
240
+ }
241
+
242
+ return lines.join('\n').trimEnd();
243
+ }
244
+
245
+ /**
246
+ * Show detailed help for a single unimplemented command.
247
+ * Includes command name, description, usage, args, and status.
248
+ * @param {string} name - Command name
249
+ * @returns {string} Formatted help text
250
+ */
251
+ function showCommandHelp(name) {
252
+ const cmd = COMMANDS.find(c => c.name === name);
253
+ if (!cmd) return null;
254
+
255
+ let text = `[brain] /brain:${cmd.name} -- ${cmd.description}\n\nUsage: ${cmd.usage}`;
256
+ if (cmd.args) {
257
+ text += `\n${cmd.args}`;
258
+ }
259
+ text += '\n\nStatus: Coming soon.';
260
+ return text;
261
+ }
262
+
263
+ module.exports = { COMMANDS, getCommandHelp, showHelp, showCommandHelp };
@@ -0,0 +1,138 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Complexity budget scoring module.
5
+ * Provides weighted scoring for plan complexity, budget checking,
6
+ * and estimation from plan frontmatter.
7
+ *
8
+ * No external dependencies.
9
+ */
10
+
11
+ const WEIGHTS = {
12
+ fileCount: 1,
13
+ functionCount: 1.5,
14
+ dependencyDepth: 2,
15
+ nestingDepth: 2,
16
+ linesOfCode: 0.5
17
+ };
18
+
19
+ const BUDGETS = {
20
+ scaffolding: 80,
21
+ standard: 60,
22
+ production: 40
23
+ };
24
+
25
+ /**
26
+ * Calculate a weighted complexity score from metrics.
27
+ * @param {object} metrics - { fileCount, functionCount, dependencyDepth, nestingDepth, linesOfCode }
28
+ * @returns {number} Rounded weighted sum
29
+ */
30
+ function calculateScore(metrics) {
31
+ if (!metrics || typeof metrics !== 'object') return 0;
32
+
33
+ let sum = 0;
34
+ for (const [key, weight] of Object.entries(WEIGHTS)) {
35
+ const value = metrics[key];
36
+ if (typeof value === 'number' && !Number.isNaN(value)) {
37
+ sum += value * weight;
38
+ }
39
+ }
40
+ return Math.round(sum);
41
+ }
42
+
43
+ /**
44
+ * Check whether a score exceeds a budget.
45
+ * @param {number} score - Calculated complexity score
46
+ * @param {number} budget - Budget threshold
47
+ * @returns {object} { exceeded, score, budget, remaining|overage }
48
+ */
49
+ function checkBudget(score, budget) {
50
+ if (score > budget) {
51
+ return { exceeded: true, score, budget, overage: score - budget };
52
+ }
53
+ return { exceeded: false, score, budget, remaining: budget - score };
54
+ }
55
+
56
+ /**
57
+ * Generate a per-metric breakdown showing how each metric contributes.
58
+ * @param {object} metrics - Same shape as calculateScore input
59
+ * @returns {object} Per-metric { raw, weight, contribution }
60
+ */
61
+ function generateBreakdown(metrics) {
62
+ if (!metrics || typeof metrics !== 'object') return {};
63
+
64
+ const result = {};
65
+ for (const [key, weight] of Object.entries(WEIGHTS)) {
66
+ const raw = typeof metrics[key] === 'number' ? metrics[key] : 0;
67
+ result[key] = {
68
+ raw,
69
+ weight,
70
+ contribution: raw * weight
71
+ };
72
+ }
73
+ return result;
74
+ }
75
+
76
+ /**
77
+ * Get the default complexity budget for a phase type.
78
+ * @param {string} phaseType - 'scaffolding' | 'standard' | 'production'
79
+ * @returns {number} Budget value
80
+ */
81
+ function getDefaultBudget(phaseType) {
82
+ return BUDGETS[phaseType] ?? 60;
83
+ }
84
+
85
+ /**
86
+ * Estimate complexity metrics from plan content (frontmatter).
87
+ * Parses files_modified count and task count to produce heuristic estimates.
88
+ * @param {string} planContent - Raw plan file content
89
+ * @returns {object} { metrics, score }
90
+ */
91
+ function estimateFromPlan(planContent) {
92
+ if (!planContent || typeof planContent !== 'string') {
93
+ return { metrics: { fileCount: 0, functionCount: 0, dependencyDepth: 2, nestingDepth: 2, linesOfCode: 0 }, score: 0 };
94
+ }
95
+
96
+ // Extract frontmatter
97
+ const fmMatch = planContent.match(/^---\n([\s\S]*?)\n---/);
98
+ const frontmatter = fmMatch ? fmMatch[1] : '';
99
+
100
+ // Count files_modified entries (lines starting with " - " after files_modified:)
101
+ let fileCount = 0;
102
+ const fmLines = frontmatter.split('\n');
103
+ let inFilesModified = false;
104
+ for (const line of fmLines) {
105
+ if (line.startsWith('files_modified:')) {
106
+ inFilesModified = true;
107
+ continue;
108
+ }
109
+ if (inFilesModified) {
110
+ if (line.match(/^\s+-\s+/)) {
111
+ fileCount++;
112
+ } else {
113
+ inFilesModified = false;
114
+ }
115
+ }
116
+ }
117
+
118
+ const metrics = {
119
+ fileCount,
120
+ functionCount: fileCount * 3,
121
+ dependencyDepth: 2,
122
+ nestingDepth: 2,
123
+ linesOfCode: fileCount * 80
124
+ };
125
+
126
+ return {
127
+ metrics,
128
+ score: calculateScore(metrics)
129
+ };
130
+ }
131
+
132
+ module.exports = {
133
+ calculateScore,
134
+ checkBudget,
135
+ generateBreakdown,
136
+ getDefaultBudget,
137
+ estimateFromPlan
138
+ };
@@ -0,0 +1,108 @@
1
+ 'use strict';
2
+
3
+ const assert = require('node:assert');
4
+
5
+ // Tests for complexity.cjs
6
+ // RED phase: these should fail until implementation exists
7
+
8
+ const c = require('./complexity.cjs');
9
+
10
+ // calculateScore tests
11
+ {
12
+ const score = c.calculateScore({
13
+ fileCount: 5,
14
+ functionCount: 10,
15
+ dependencyDepth: 3,
16
+ nestingDepth: 4,
17
+ linesOfCode: 200
18
+ });
19
+ assert.strictEqual(score, 134, `calculateScore full metrics: expected 134, got ${score}`);
20
+ }
21
+
22
+ {
23
+ const score = c.calculateScore({});
24
+ assert.strictEqual(score, 0, `calculateScore empty: expected 0, got ${score}`);
25
+ }
26
+
27
+ {
28
+ const score = c.calculateScore({ fileCount: 10 });
29
+ assert.strictEqual(score, 10, `calculateScore single metric: expected 10, got ${score}`);
30
+ }
31
+
32
+ // getDefaultBudget tests
33
+ {
34
+ assert.strictEqual(c.getDefaultBudget('scaffolding'), 80);
35
+ assert.strictEqual(c.getDefaultBudget('standard'), 60);
36
+ assert.strictEqual(c.getDefaultBudget('production'), 40);
37
+ assert.strictEqual(c.getDefaultBudget('unknown'), 60);
38
+ assert.strictEqual(c.getDefaultBudget(), 60);
39
+ }
40
+
41
+ // checkBudget tests
42
+ {
43
+ const under = c.checkBudget(50, 60);
44
+ assert.strictEqual(under.exceeded, false);
45
+ assert.strictEqual(under.score, 50);
46
+ assert.strictEqual(under.budget, 60);
47
+ assert.strictEqual(under.remaining, 10);
48
+ assert.strictEqual('overage' in under, false);
49
+ }
50
+
51
+ {
52
+ const over = c.checkBudget(70, 60);
53
+ assert.strictEqual(over.exceeded, true);
54
+ assert.strictEqual(over.score, 70);
55
+ assert.strictEqual(over.budget, 60);
56
+ assert.strictEqual(over.overage, 10);
57
+ assert.strictEqual('remaining' in over, false);
58
+ }
59
+
60
+ {
61
+ const exact = c.checkBudget(60, 60);
62
+ assert.strictEqual(exact.exceeded, false);
63
+ assert.strictEqual(exact.remaining, 0);
64
+ }
65
+
66
+ // generateBreakdown tests
67
+ {
68
+ const breakdown = c.generateBreakdown({
69
+ fileCount: 5,
70
+ functionCount: 10,
71
+ dependencyDepth: 3,
72
+ nestingDepth: 4,
73
+ linesOfCode: 200
74
+ });
75
+ assert.strictEqual(breakdown.fileCount.raw, 5);
76
+ assert.strictEqual(breakdown.fileCount.weight, 1);
77
+ assert.strictEqual(breakdown.fileCount.contribution, 5);
78
+ assert.strictEqual(breakdown.functionCount.contribution, 15);
79
+ assert.strictEqual(breakdown.linesOfCode.contribution, 100);
80
+ }
81
+
82
+ // estimateFromPlan tests
83
+ {
84
+ const planContent = `---
85
+ phase: 01-foundation
86
+ plan: 01
87
+ files_modified:
88
+ - src/a.js
89
+ - src/b.js
90
+ - src/c.js
91
+ ---
92
+
93
+ <tasks>
94
+ <task type="auto">Task 1</task>
95
+ <task type="auto">Task 2</task>
96
+ </tasks>`;
97
+
98
+ const est = c.estimateFromPlan(planContent);
99
+ assert.strictEqual(est.metrics.fileCount, 3);
100
+ assert.strictEqual(est.metrics.functionCount, 9); // 3 * 3
101
+ assert.strictEqual(est.metrics.dependencyDepth, 2);
102
+ assert.strictEqual(est.metrics.nestingDepth, 2);
103
+ assert.strictEqual(est.metrics.linesOfCode, 240); // 3 * 80
104
+ assert.strictEqual(typeof est.score, 'number');
105
+ assert.ok(est.score > 0);
106
+ }
107
+
108
+ console.log('All complexity tests passed');