brain-dev 1.1.1 → 1.2.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/README.md CHANGED
@@ -185,6 +185,16 @@ pending → discussing → discussed → planning → executing → executed →
185
185
 
186
186
  Every command knows what comes next. `brain-dev progress` always tells you the right next step.
187
187
 
188
+ ## Auto Update Notification
189
+
190
+ Brain checks for newer versions on session start (background, non-blocking). If an update is available, the statusline shows:
191
+
192
+ ```
193
+ ⬆ /brain:upgrade | brain | [########--] 78% | P2: executing
194
+ ```
195
+
196
+ Type `/brain:upgrade` to see the upgrade command and clear the notification.
197
+
188
198
  ## Zero Dependencies
189
199
 
190
200
  Brain is a single npm package with zero runtime dependencies. Just Node.js 22+.
@@ -178,6 +178,12 @@ async function main() {
178
178
  await require('./lib/commands/update.cjs').run(args.slice(1));
179
179
  break;
180
180
 
181
+ case 'upgrade':
182
+ await require('./lib/commands/upgrade.cjs').run(args.slice(1), {
183
+ brainDir: path.join(process.cwd(), '.brain')
184
+ });
185
+ break;
186
+
181
187
  case 'health':
182
188
  await require('./lib/commands/health.cjs').run(args.slice(1));
183
189
  break;
@@ -0,0 +1,48 @@
1
+ 'use strict';
2
+ const fs = require('node:fs');
3
+ const path = require('node:path');
4
+ const { output, prefix } = require('../core.cjs');
5
+
6
+ async function run(args = [], opts = {}) {
7
+ const brainDir = opts.brainDir || path.join(process.cwd(), '.brain');
8
+
9
+ // Read cache
10
+ const cachePath = path.join(brainDir, '.update-check.json');
11
+ let cache = null;
12
+ try {
13
+ cache = JSON.parse(fs.readFileSync(cachePath, 'utf8'));
14
+ } catch {}
15
+
16
+ if (!cache || !cache.update_available) {
17
+ const lines = [
18
+ prefix('You are on the latest version.'),
19
+ prefix(`Installed: ${cache?.installed || 'unknown'}`)
20
+ ];
21
+ output({ action: 'up-to-date', installed: cache?.installed || 'unknown' }, lines.join('\n'));
22
+ return { action: 'up-to-date' };
23
+ }
24
+
25
+ // Show upgrade info
26
+ const lines = [
27
+ prefix(`Update available: ${cache.installed} → ${cache.latest}`),
28
+ '',
29
+ prefix('To upgrade, run:'),
30
+ prefix(` npx brain-dev@${cache.latest} update`),
31
+ '',
32
+ prefix('Or update globally:'),
33
+ prefix(' npm install -g brain-dev@latest'),
34
+ '',
35
+ prefix('After updating, restart Claude Code to pick up new features.')
36
+ ];
37
+
38
+ output({
39
+ action: 'upgrade-available',
40
+ installed: cache.installed,
41
+ latest: cache.latest,
42
+ command: `npx brain-dev@${cache.latest} update`
43
+ }, lines.join('\n'));
44
+
45
+ return { action: 'upgrade-available', installed: cache.installed, latest: cache.latest };
46
+ }
47
+
48
+ module.exports = { run };
@@ -234,6 +234,15 @@ const COMMANDS = [
234
234
  needsState: false,
235
235
  args: ' --fix Enable aggressive repair of hooks and templates\n --quick Run safe checks only (used by bootstrap)\n --json Force JSON output'
236
236
  },
237
+ {
238
+ name: 'upgrade',
239
+ description: 'Check and apply Brain updates',
240
+ usage: 'brain-dev upgrade',
241
+ group: 'Meta',
242
+ implemented: true,
243
+ needsState: false,
244
+ args: ''
245
+ },
237
246
  {
238
247
  name: 'version',
239
248
  description: 'Show brain-dev version',
package/bin/lib/init.cjs CHANGED
@@ -249,10 +249,18 @@ async function run(args = []) {
249
249
  fs.chmodSync(path.join(brainDir, 'hooks', 'post-tool-use.sh'), 0o755);
250
250
  }
251
251
 
252
+ // Copy update check hook
253
+ const checkUpdateSrc = packagePath('hooks', 'check-update.sh');
254
+ if (fs.existsSync(checkUpdateSrc)) {
255
+ fs.copyFileSync(checkUpdateSrc, path.join(brainDir, 'hooks', 'check-update.sh'));
256
+ fs.chmodSync(path.join(brainDir, 'hooks', 'check-update.sh'), 0o755);
257
+ }
258
+
252
259
  // Write .gitignore
253
260
  const gitignoreContent = [
254
261
  '*.tmp',
255
262
  '*.lock',
263
+ '.update-check.json',
256
264
  'storm/fragments/',
257
265
  'storm/events.jsonl',
258
266
  ''
@@ -0,0 +1,20 @@
1
+ ---
2
+ name: brain:upgrade
3
+ description: Check for and apply Brain updates
4
+ allowed-tools:
5
+ - Read
6
+ - Bash
7
+ ---
8
+ <objective>
9
+ Check if a newer version of brain-dev is available and show upgrade instructions.
10
+ </objective>
11
+
12
+ <process>
13
+ 1. Run: `npx brain-dev upgrade`
14
+ 2. Brain will:
15
+ - Check the cached update status from `.brain/.update-check.json`
16
+ - Show current vs latest version if an update is available
17
+ - Provide the exact command to run for upgrading
18
+ - Clear the update notification from the statusline
19
+ 3. If already up to date, confirms the current version.
20
+ </process>
@@ -48,7 +48,7 @@ try {
48
48
  'Phase: ' + (data.phase && data.phase.current || 0) + ' (' + (data.phase && data.phase.status || 'initialized') + ')',
49
49
  'Next: ' + (data.nextAction || '/brain:new-project'),
50
50
  '',
51
- 'Commands: /brain:new-project, /brain:story, /brain:discuss, /brain:plan, /brain:execute, /brain:verify, /brain:complete, /brain:quick, /brain:new-task, /brain:progress, /brain:pause, /brain:resume, /brain:help, /brain:health, /brain:update, /brain:storm, /brain:adr, /brain:phase, /brain:config, /brain:map, /brain:recover, /brain:dashboard, /brain:auto (or execute --auto)',
51
+ 'Commands: /brain:new-project, /brain:story, /brain:discuss, /brain:plan, /brain:execute, /brain:verify, /brain:complete, /brain:quick, /brain:new-task, /brain:progress, /brain:pause, /brain:resume, /brain:help, /brain:health, /brain:update, /brain:upgrade, /brain:storm, /brain:adr, /brain:phase, /brain:config, /brain:map, /brain:recover, /brain:dashboard, /brain:auto (or execute --auto)',
52
52
  '',
53
53
  'Instructions for Claude:',
54
54
  '- When user types /brain:<command>, run: npx brain-dev <command> [args]',
@@ -66,3 +66,8 @@ try {
66
66
  if [ -f "$BRAIN_DIR/brain.json" ]; then
67
67
  npx brain-dev health --quick 2>/dev/null
68
68
  fi
69
+
70
+ # Background update check (non-blocking)
71
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
72
+ bash "$SCRIPT_DIR/check-update.sh" "$BRAIN_DIR" &>/dev/null &
73
+ disown
@@ -0,0 +1,37 @@
1
+ #!/bin/bash
2
+ # Background npm version check — writes result to .brain/.update-check.json
3
+ # Called by bootstrap.sh with & (background, non-blocking)
4
+
5
+ BRAIN_DIR="${1:-.brain}"
6
+ CACHE_FILE="$BRAIN_DIR/.update-check.json"
7
+
8
+ # Read installed version from package
9
+ INSTALLED=$(node -e "try{console.log(require('brain-dev/package.json').version)}catch{console.log('unknown')}" 2>/dev/null)
10
+ if [ "$INSTALLED" = "unknown" ] || [ -z "$INSTALLED" ]; then
11
+ INSTALLED=$(npx brain-dev version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1)
12
+ fi
13
+
14
+ # Query npm for latest (10 second timeout)
15
+ LATEST=$(timeout 10 npm view brain-dev version 2>/dev/null)
16
+
17
+ if [ -z "$LATEST" ]; then
18
+ # npm unavailable or timeout — skip silently
19
+ exit 0
20
+ fi
21
+
22
+ # Trim whitespace to prevent false positives
23
+ INSTALLED=$(echo "$INSTALLED" | tr -d '[:space:]')
24
+ LATEST=$(echo "$LATEST" | tr -d '[:space:]')
25
+
26
+ # Write cache safely using node (prevents JSON injection from malformed version strings)
27
+ node -e "
28
+ const fs = require('fs');
29
+ const installed = process.argv[1];
30
+ const latest = process.argv[2];
31
+ fs.writeFileSync(process.argv[3], JSON.stringify({
32
+ update_available: installed !== latest,
33
+ installed: installed,
34
+ latest: latest,
35
+ checked: Math.floor(Date.now() / 1000)
36
+ }));
37
+ " "$INSTALLED" "$LATEST" "$CACHE_FILE"
@@ -125,6 +125,18 @@ node -e "
125
125
  phaseDisplay = ' | P' + phaseCurrent + (phaseStatus ? ': ' + phaseStatus : '');
126
126
  }
127
127
 
128
+ // Read update cache for upgrade notification
129
+ let updatePrefix = '';
130
+ try {
131
+ const cachePath = '$BRAIN_DIR/.update-check.json';
132
+ if (fs.existsSync(cachePath)) {
133
+ const cache = JSON.parse(fs.readFileSync(cachePath, 'utf8'));
134
+ if (cache.update_available === true) {
135
+ updatePrefix = '\x1b[33m\u2B06 /brain:upgrade\x1b[0m | ';
136
+ }
137
+ }
138
+ } catch {}
139
+
128
140
  // Output status line to stdout
129
- process.stdout.write(projectName + phaseDisplay + ' | ' + bar);
141
+ process.stdout.write(updatePrefix + projectName + phaseDisplay + ' | ' + bar);
130
142
  " "$input" 2>/dev/null || echo "brain | ---"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "brain-dev",
3
- "version": "1.1.1",
3
+ "version": "1.2.0",
4
4
  "description": "AI-powered development workflow orchestrator",
5
5
  "author": "halilcosdu",
6
6
  "license": "MIT",