@brainjar/cli 0.4.0 → 0.5.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 +3 -2
- package/package.json +3 -3
- package/src/cli.ts +4 -0
- package/src/client.ts +5 -4
- package/src/commands/context.ts +220 -0
- package/src/commands/init.ts +16 -11
- package/src/commands/persona.ts +55 -0
- package/src/commands/rules.ts +44 -3
- package/src/commands/server.ts +34 -59
- package/src/commands/soul.ts +50 -0
- package/src/commands/upgrade.ts +35 -0
- package/src/config.ts +229 -38
- package/src/daemon.ts +72 -25
- package/src/errors.ts +20 -0
- package/src/upgrade.ts +121 -0
- package/src/version-check.ts +2 -2
package/src/upgrade.ts
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { execFile } from 'node:child_process'
|
|
2
|
+
import {
|
|
3
|
+
healthCheck,
|
|
4
|
+
start,
|
|
5
|
+
stop,
|
|
6
|
+
status as daemonStatus,
|
|
7
|
+
upgradeServer,
|
|
8
|
+
} from './daemon.js'
|
|
9
|
+
import { checkForUpdates } from './version-check.js'
|
|
10
|
+
import { ErrorCode, createError } from './errors.js'
|
|
11
|
+
import pkg from '../package.json'
|
|
12
|
+
|
|
13
|
+
export interface ComponentResult {
|
|
14
|
+
upgraded: boolean
|
|
15
|
+
from: string
|
|
16
|
+
to: string
|
|
17
|
+
message?: string
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface ServerResult extends ComponentResult {
|
|
21
|
+
restarted?: boolean
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface UpgradeResult {
|
|
25
|
+
cli?: ComponentResult
|
|
26
|
+
server?: ServerResult
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Detect which package manager installed brainjar.
|
|
31
|
+
* Checks the runtime binary path first, then falls back to npm.
|
|
32
|
+
*/
|
|
33
|
+
export function detectPackageManager(): 'bun' | 'npm' {
|
|
34
|
+
const argv0 = process.argv[0] ?? ''
|
|
35
|
+
if (argv0.includes('bun')) return 'bun'
|
|
36
|
+
return 'npm'
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** Shell out to a package manager and capture stdout/stderr. */
|
|
40
|
+
function exec(cmd: string, args: string[]): Promise<{ stdout: string; stderr: string }> {
|
|
41
|
+
return new Promise((resolve, reject) => {
|
|
42
|
+
execFile(cmd, args, { timeout: 120_000 }, (error, stdout, stderr) => {
|
|
43
|
+
if (error) reject(Object.assign(error, { stderr }))
|
|
44
|
+
else resolve({ stdout, stderr })
|
|
45
|
+
})
|
|
46
|
+
})
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Upgrade the CLI npm package to latest.
|
|
51
|
+
*/
|
|
52
|
+
export async function upgradeCli(): Promise<ComponentResult> {
|
|
53
|
+
const currentVersion = pkg.version
|
|
54
|
+
|
|
55
|
+
// Check if already on latest
|
|
56
|
+
const updates = await checkForUpdates(currentVersion)
|
|
57
|
+
if (!updates?.cli) {
|
|
58
|
+
return { upgraded: false, from: currentVersion, to: currentVersion, message: 'Already on latest version' }
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const latestVersion = updates.cli.latest
|
|
62
|
+
const pm = detectPackageManager()
|
|
63
|
+
|
|
64
|
+
try {
|
|
65
|
+
if (pm === 'bun') {
|
|
66
|
+
await exec('bun', ['install', '-g', `@brainjar/cli@${latestVersion}`])
|
|
67
|
+
} else {
|
|
68
|
+
await exec('npm', ['install', '-g', `@brainjar/cli@${latestVersion}`])
|
|
69
|
+
}
|
|
70
|
+
} catch (e: any) {
|
|
71
|
+
const stderr = e.stderr ?? e.message ?? ''
|
|
72
|
+
const isPermission = stderr.includes('EACCES') || stderr.includes('permission')
|
|
73
|
+
throw createError(ErrorCode.SHELL_ERROR, {
|
|
74
|
+
message: `Failed to upgrade CLI via ${pm}: ${stderr.trim()}`,
|
|
75
|
+
hint: isPermission
|
|
76
|
+
? `Try running with sudo, or fix npm permissions: https://docs.npmjs.com/resolving-eacces-permissions-errors-when-installing-packages-globally`
|
|
77
|
+
: 'Check your network connection and try again.',
|
|
78
|
+
})
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return { upgraded: true, from: currentVersion, to: latestVersion }
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Upgrade the server binary. Handles stop/restart lifecycle.
|
|
86
|
+
*/
|
|
87
|
+
export async function upgradeServerBinary(): Promise<ServerResult> {
|
|
88
|
+
const { getInstalledServerVersion } = await import('./version-check.js')
|
|
89
|
+
const installedVersion = (await getInstalledServerVersion()) ?? 'unknown'
|
|
90
|
+
|
|
91
|
+
// Stop server if running before replacing binary
|
|
92
|
+
const s = await daemonStatus()
|
|
93
|
+
const wasRunning = s.running
|
|
94
|
+
|
|
95
|
+
if (wasRunning) {
|
|
96
|
+
await stop()
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const result = await upgradeServer()
|
|
100
|
+
|
|
101
|
+
if (result.alreadyLatest) {
|
|
102
|
+
if (wasRunning) await start()
|
|
103
|
+
return { upgraded: false, from: installedVersion, to: result.version, message: 'Already on latest version' }
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Restart if it was running
|
|
107
|
+
if (wasRunning) {
|
|
108
|
+
await start()
|
|
109
|
+
const deadline = Date.now() + 10_000
|
|
110
|
+
while (Date.now() < deadline) {
|
|
111
|
+
await new Promise(r => setTimeout(r, 200))
|
|
112
|
+
const check = await healthCheck({ timeout: 2000 })
|
|
113
|
+
if (check.healthy) {
|
|
114
|
+
return { upgraded: true, from: installedVersion, to: result.version, restarted: true }
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return { upgraded: true, from: installedVersion, to: result.version, restarted: false, message: 'Upgraded but failed health check after restart' }
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return { upgraded: true, from: installedVersion, to: result.version }
|
|
121
|
+
}
|
package/src/version-check.ts
CHANGED
|
@@ -126,11 +126,11 @@ export async function renderUpdateBanner(currentCliVersion: string): Promise<str
|
|
|
126
126
|
const lines: string[] = []
|
|
127
127
|
|
|
128
128
|
if (updates.cli) {
|
|
129
|
-
lines.push(` ⬆ brainjar ${updates.cli.latest} available (current: ${updates.cli.current}) —
|
|
129
|
+
lines.push(` ⬆ brainjar ${updates.cli.latest} available (current: ${updates.cli.current}) — brainjar upgrade`)
|
|
130
130
|
}
|
|
131
131
|
|
|
132
132
|
if (updates.server) {
|
|
133
|
-
lines.push(` ⬆ server ${updates.server.latest} available (current: ${updates.server.current}) — brainjar
|
|
133
|
+
lines.push(` ⬆ server ${updates.server.latest} available (current: ${updates.server.current}) — brainjar upgrade`)
|
|
134
134
|
}
|
|
135
135
|
|
|
136
136
|
return lines.length > 0 ? lines.join('\n') : undefined
|