@swarmclawai/swarmclaw 1.0.0 → 1.0.2

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.
@@ -0,0 +1,149 @@
1
+ #!/usr/bin/env node
2
+ 'use strict'
3
+
4
+ /* eslint-disable @typescript-eslint/no-require-imports */
5
+ const fs = require('node:fs')
6
+ const path = require('node:path')
7
+
8
+ const { readPackageVersion } = require('./install-root.js')
9
+ const {
10
+ PKG_ROOT,
11
+ SWARMCLAW_HOME,
12
+ findStandaloneServer,
13
+ isGitCheckout,
14
+ } = require('./server-cmd.js')
15
+
16
+ function readPid(pidFile) {
17
+ try {
18
+ const pid = Number.parseInt(fs.readFileSync(pidFile, 'utf8').trim(), 10)
19
+ return Number.isFinite(pid) ? pid : null
20
+ } catch {
21
+ return null
22
+ }
23
+ }
24
+
25
+ function isProcessRunning(pid) {
26
+ try {
27
+ process.kill(pid, 0)
28
+ return true
29
+ } catch {
30
+ return false
31
+ }
32
+ }
33
+
34
+ function buildDoctorReport(opts = {}) {
35
+ const pkgRoot = opts.pkgRoot || PKG_ROOT
36
+ const homeDir = opts.homeDir || SWARMCLAW_HOME
37
+ const pidFile = path.join(homeDir, 'server.pid')
38
+ const dataDir = path.join(homeDir, 'data')
39
+ const workspaceDir = path.join(homeDir, 'workspace')
40
+ const browserProfilesDir = path.join(homeDir, 'browser-profiles')
41
+ const nextCliPath = path.join(pkgRoot, 'node_modules', 'next', 'dist', 'bin', 'next')
42
+ const standaloneServer = findStandaloneServer({ pkgRoot })
43
+ const pid = readPid(pidFile)
44
+ const running = pid ? isProcessRunning(pid) : false
45
+
46
+ const serverState = !pid
47
+ ? 'not-running'
48
+ : running
49
+ ? 'running'
50
+ : 'stale-pid'
51
+
52
+ const recommendations = []
53
+ if (!standaloneServer) {
54
+ if (fs.existsSync(nextCliPath)) {
55
+ recommendations.push('Standalone bundle is missing. Run `swarmclaw run` to build it automatically or `swarmclaw server --build` to prebuild it now.')
56
+ } else {
57
+ recommendations.push('Next.js build dependencies are missing from this install. Reinstall the package before starting SwarmClaw.')
58
+ }
59
+ }
60
+ if (serverState === 'stale-pid') {
61
+ recommendations.push('A stale PID file was found. Run `swarmclaw stop` to clean it up.')
62
+ }
63
+
64
+ return {
65
+ packageVersion: readPackageVersion(pkgRoot) || 'unknown',
66
+ packageRoot: pkgRoot,
67
+ installKind: isGitCheckout(pkgRoot) ? 'git' : 'package',
68
+ homeDir,
69
+ dataDir,
70
+ workspaceDir,
71
+ browserProfilesDir,
72
+ server: {
73
+ state: serverState,
74
+ pid,
75
+ pidFile,
76
+ },
77
+ build: {
78
+ standaloneServer,
79
+ nextCliPresent: fs.existsSync(nextCliPath),
80
+ nextCliPath,
81
+ },
82
+ recommendations,
83
+ }
84
+ }
85
+
86
+ function printHelp() {
87
+ process.stdout.write(`
88
+ Usage: swarmclaw doctor [--json]
89
+
90
+ Show local installation and build diagnostics for SwarmClaw.
91
+ `.trim() + '\n')
92
+ }
93
+
94
+ function printHumanReport(report) {
95
+ const lines = [
96
+ `Package version: ${report.packageVersion}`,
97
+ `Install kind: ${report.installKind}`,
98
+ `Package root: ${report.packageRoot}`,
99
+ `Home: ${report.homeDir}`,
100
+ `Data: ${report.dataDir}`,
101
+ `Workspace: ${report.workspaceDir}`,
102
+ `Browser profiles: ${report.browserProfilesDir}`,
103
+ `Server: ${report.server.state}${report.server.pid ? ` (PID: ${report.server.pid})` : ''}`,
104
+ `Standalone bundle: ${report.build.standaloneServer ? `yes (${report.build.standaloneServer})` : 'no'}`,
105
+ `Next CLI available: ${report.build.nextCliPresent ? 'yes' : 'no'}`,
106
+ ]
107
+
108
+ if (report.recommendations.length > 0) {
109
+ lines.push('', 'Recommendations:')
110
+ for (const recommendation of report.recommendations) {
111
+ lines.push(`- ${recommendation}`)
112
+ }
113
+ }
114
+
115
+ process.stdout.write(`${lines.join('\n')}\n`)
116
+ }
117
+
118
+ function main(args = process.argv.slice(3)) {
119
+ const json = args.includes('--json')
120
+ if (args.includes('-h') || args.includes('--help')) {
121
+ printHelp()
122
+ process.exit(0)
123
+ }
124
+
125
+ const unknown = args.filter((arg) => arg !== '--json')
126
+ if (unknown.length > 0) {
127
+ process.stderr.write(`[swarmclaw] Unknown argument: ${unknown[0]}\n`)
128
+ printHelp()
129
+ process.exit(1)
130
+ }
131
+
132
+ const report = buildDoctorReport()
133
+ if (json) {
134
+ process.stdout.write(`${JSON.stringify(report, null, 2)}\n`)
135
+ return
136
+ }
137
+ printHumanReport(report)
138
+ }
139
+
140
+ if (require.main === module) {
141
+ main()
142
+ }
143
+
144
+ module.exports = {
145
+ buildDoctorReport,
146
+ isProcessRunning,
147
+ main,
148
+ readPid,
149
+ }
@@ -0,0 +1,50 @@
1
+ 'use strict'
2
+ /* eslint-disable @typescript-eslint/no-require-imports */
3
+
4
+ const test = require('node:test')
5
+ const assert = require('node:assert/strict')
6
+ const fs = require('node:fs')
7
+ const os = require('node:os')
8
+ const path = require('node:path')
9
+
10
+ const { buildDoctorReport } = require('./doctor-cmd.js')
11
+
12
+ test('buildDoctorReport recommends a local build when standalone output is missing', () => {
13
+ const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'swarmclaw-doctor-'))
14
+ const pkgRoot = path.join(tempDir, 'pkg')
15
+ const homeDir = path.join(tempDir, '.swarmclaw')
16
+ const nextCli = path.join(pkgRoot, 'node_modules', 'next', 'dist', 'bin', 'next')
17
+
18
+ fs.mkdirSync(path.dirname(nextCli), { recursive: true })
19
+ fs.mkdirSync(homeDir, { recursive: true })
20
+ fs.writeFileSync(path.join(pkgRoot, 'package.json'), JSON.stringify({ name: '@swarmclawai/swarmclaw', version: '1.0.1' }), 'utf8')
21
+ fs.writeFileSync(nextCli, '#!/usr/bin/env node\n', 'utf8')
22
+
23
+ const report = buildDoctorReport({ pkgRoot, homeDir })
24
+
25
+ assert.equal(report.installKind, 'package')
26
+ assert.equal(report.build.nextCliPresent, true)
27
+ assert.equal(report.build.standaloneServer, null)
28
+ assert.match(report.recommendations.join('\n'), /swarmclaw run/)
29
+
30
+ fs.rmSync(tempDir, { recursive: true, force: true })
31
+ })
32
+
33
+ test('buildDoctorReport flags stale PID files', () => {
34
+ const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'swarmclaw-doctor-stale-'))
35
+ const pkgRoot = path.join(tempDir, 'pkg')
36
+ const homeDir = path.join(tempDir, '.swarmclaw')
37
+ const pidFile = path.join(homeDir, 'server.pid')
38
+
39
+ fs.mkdirSync(homeDir, { recursive: true })
40
+ fs.mkdirSync(pkgRoot, { recursive: true })
41
+ fs.writeFileSync(path.join(pkgRoot, 'package.json'), JSON.stringify({ name: '@swarmclawai/swarmclaw', version: '1.0.1' }), 'utf8')
42
+ fs.writeFileSync(pidFile, '999999\n', 'utf8')
43
+
44
+ const report = buildDoctorReport({ pkgRoot, homeDir })
45
+
46
+ assert.equal(report.server.state, 'stale-pid')
47
+ assert.match(report.recommendations.join('\n'), /swarmclaw stop/)
48
+
49
+ fs.rmSync(tempDir, { recursive: true, force: true })
50
+ })
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  'use strict'
3
3
 
4
+ /* eslint-disable @typescript-eslint/no-require-imports */
4
5
  const fs = require('node:fs')
5
6
  const os = require('node:os')
6
7
  const path = require('node:path')
@@ -143,13 +144,51 @@ function detectGlobalInstallManagerForRoot(pkgRoot, execImpl = execFileSync, env
143
144
  return null
144
145
  }
145
146
 
147
+ function findLocalInstallProjectRoot(pkgRoot) {
148
+ const normalized = normalizeDir(pkgRoot)
149
+ if (!normalized) return null
150
+
151
+ const marker = `${path.sep}node_modules${path.sep}`
152
+ const idx = normalized.indexOf(marker)
153
+ if (idx === -1) return null
154
+
155
+ const projectRoot = normalized.slice(0, idx)
156
+ return projectRoot ? path.resolve(projectRoot) : path.parse(normalized).root
157
+ }
158
+
159
+ function resolveStateHome(opts = {}) {
160
+ const env = opts.env || process.env
161
+ const explicitHome = normalizeDir(env.SWARMCLAW_HOME)
162
+ if (explicitHome) return explicitHome
163
+
164
+ const pkgRoot = normalizeDir(opts.pkgRoot)
165
+ || resolvePackageRoot({
166
+ moduleDir: opts.moduleDir,
167
+ argv1: opts.argv1,
168
+ cwd: opts.cwd,
169
+ })
170
+ if (!pkgRoot) return path.join(os.homedir(), '.swarmclaw')
171
+
172
+ const execImpl = opts.execImpl || execFileSync
173
+ if (detectGlobalInstallManagerForRoot(pkgRoot, execImpl, env)) {
174
+ return path.join(os.homedir(), '.swarmclaw')
175
+ }
176
+
177
+ const projectRoot = findLocalInstallProjectRoot(pkgRoot)
178
+ if (projectRoot) return path.join(projectRoot, '.swarmclaw')
179
+
180
+ return path.join(os.homedir(), '.swarmclaw')
181
+ }
182
+
146
183
  module.exports = {
147
184
  PACKAGE_NAME,
148
185
  candidateDirsFromArgv1,
149
186
  detectGlobalInstallManagerForRoot,
150
187
  findPackageRoot,
188
+ findLocalInstallProjectRoot,
151
189
  readPackageName,
152
190
  readPackageVersion,
153
191
  resolveGlobalRoot,
154
192
  resolvePackageRoot,
193
+ resolveStateHome,
155
194
  }
@@ -10,7 +10,9 @@ const path = require('node:path')
10
10
  const {
11
11
  candidateDirsFromArgv1,
12
12
  detectGlobalInstallManagerForRoot,
13
+ findLocalInstallProjectRoot,
13
14
  resolvePackageRoot,
15
+ resolveStateHome,
14
16
  } = require('./install-root.js')
15
17
 
16
18
  test('candidateDirsFromArgv1 includes the package directory for node_modules/.bin launchers', () => {
@@ -59,3 +61,61 @@ test('detectGlobalInstallManagerForRoot matches the owning global root by realpa
59
61
 
60
62
  fs.rmSync(rootDir, { recursive: true, force: true })
61
63
  })
64
+
65
+ test('findLocalInstallProjectRoot returns the project root for nested pnpm installs', () => {
66
+ const pkgRoot = path.join(
67
+ '/tmp',
68
+ 'example',
69
+ 'node_modules',
70
+ '.pnpm',
71
+ '@swarmclawai+swarmclaw@1.0.1',
72
+ 'node_modules',
73
+ '@swarmclawai',
74
+ 'swarmclaw',
75
+ )
76
+
77
+ assert.equal(findLocalInstallProjectRoot(pkgRoot), path.join('/tmp', 'example'))
78
+ })
79
+
80
+ test('resolveStateHome prefers the local project .swarmclaw directory for local installs', () => {
81
+ const projectRoot = path.join('/tmp', 'example')
82
+ const pkgRoot = path.join(projectRoot, 'node_modules', '@swarmclawai', 'swarmclaw')
83
+ const execImpl = () => {
84
+ throw new Error('unexpected global root lookup')
85
+ }
86
+
87
+ assert.equal(
88
+ resolveStateHome({
89
+ pkgRoot,
90
+ env: {},
91
+ execImpl,
92
+ }),
93
+ path.join(projectRoot, '.swarmclaw'),
94
+ )
95
+ })
96
+
97
+ test('resolveStateHome keeps global installs under the user home directory', () => {
98
+ const rootDir = fs.mkdtempSync(path.join(os.tmpdir(), 'swarmclaw-state-home-'))
99
+ const npmGlobalRoot = path.join(rootDir, 'npm-global')
100
+ const pkgRoot = path.join(npmGlobalRoot, '@swarmclawai', 'swarmclaw')
101
+
102
+ fs.mkdirSync(path.join(npmGlobalRoot, '@swarmclawai'), { recursive: true })
103
+ fs.mkdirSync(pkgRoot, { recursive: true })
104
+
105
+ const execImpl = (command, args) => {
106
+ if (command === 'npm' && args.join(' ') === 'root -g') return npmGlobalRoot
107
+ if (command === 'pnpm' && args.join(' ') === 'root -g') return path.join(rootDir, 'pnpm-global')
108
+ throw new Error(`unexpected command: ${command} ${args.join(' ')}`)
109
+ }
110
+
111
+ assert.equal(
112
+ resolveStateHome({
113
+ pkgRoot,
114
+ env: {},
115
+ execImpl,
116
+ }),
117
+ path.join(os.homedir(), '.swarmclaw'),
118
+ )
119
+
120
+ fs.rmSync(rootDir, { recursive: true, force: true })
121
+ })
package/bin/server-cmd.js CHANGED
@@ -5,7 +5,6 @@
5
5
  const fs = require('node:fs')
6
6
  const path = require('node:path')
7
7
  const { spawn, execFileSync } = require('node:child_process')
8
- const os = require('node:os')
9
8
  const {
10
9
  detectPackageManager,
11
10
  getInstallCommand,
@@ -13,21 +12,30 @@ const {
13
12
  const {
14
13
  readPackageVersion,
15
14
  resolvePackageRoot,
15
+ resolveStateHome,
16
16
  } = require('./install-root.js')
17
17
 
18
18
  // ---------------------------------------------------------------------------
19
19
  // Paths
20
20
  // ---------------------------------------------------------------------------
21
21
 
22
- const SWARMCLAW_HOME = process.env.SWARMCLAW_HOME || path.join(os.homedir(), '.swarmclaw')
23
22
  const PKG_ROOT = resolvePackageRoot({
24
23
  moduleDir: __dirname,
25
24
  argv1: process.argv[1],
26
25
  cwd: process.cwd(),
27
26
  })
27
+ const SWARMCLAW_HOME = resolveStateHome({
28
+ pkgRoot: PKG_ROOT,
29
+ moduleDir: __dirname,
30
+ argv1: process.argv[1],
31
+ cwd: process.cwd(),
32
+ env: process.env,
33
+ })
28
34
  const PID_FILE = path.join(SWARMCLAW_HOME, 'server.pid')
29
35
  const LOG_FILE = path.join(SWARMCLAW_HOME, 'server.log')
30
36
  const DATA_DIR = path.join(SWARMCLAW_HOME, 'data')
37
+ const WORKSPACE_DIR = path.join(SWARMCLAW_HOME, 'workspace')
38
+ const BROWSER_PROFILES_DIR = path.join(SWARMCLAW_HOME, 'browser-profiles')
31
39
 
32
40
  // ---------------------------------------------------------------------------
33
41
  // Helpers
@@ -67,6 +75,10 @@ function resolveStandaloneBase(pkgRoot = PKG_ROOT) {
67
75
  return path.join(pkgRoot, '.next', 'standalone')
68
76
  }
69
77
 
78
+ function isGitCheckout(pkgRoot = PKG_ROOT) {
79
+ return fs.existsSync(path.join(pkgRoot, '.git'))
80
+ }
81
+
70
82
  function getVersion() {
71
83
  return readPackageVersion(PKG_ROOT) || 'unknown'
72
84
  }
@@ -99,11 +111,12 @@ function runBuild({ pkgRoot = PKG_ROOT } = {}) {
99
111
  const nextCli = ensurePackageDependencies(pkgRoot)
100
112
 
101
113
  log('Building Next.js application (this may take a minute)...')
102
- execFileSync(process.execPath, [nextCli, 'build'], {
114
+ execFileSync(process.execPath, [nextCli, 'build', '--webpack'], {
103
115
  cwd: pkgRoot,
104
116
  stdio: 'inherit',
105
117
  env: {
106
118
  ...process.env,
119
+ SWARMCLAW_HOME,
107
120
  DATA_DIR,
108
121
  SWARMCLAW_BUILD_MODE: '1',
109
122
  },
@@ -162,7 +175,10 @@ function startServer(opts, { pkgRoot = PKG_ROOT } = {}) {
162
175
 
163
176
  const env = {
164
177
  ...process.env,
178
+ SWARMCLAW_HOME,
165
179
  DATA_DIR,
180
+ WORKSPACE_DIR,
181
+ BROWSER_PROFILES_DIR,
166
182
  HOSTNAME: host,
167
183
  PORT: port,
168
184
  WS_PORT: wsPort,
@@ -170,6 +186,7 @@ function startServer(opts, { pkgRoot = PKG_ROOT } = {}) {
170
186
 
171
187
  log(`Starting server on ${host}:${port} (WebSocket: ${wsPort})...`)
172
188
  log(`Package root: ${pkgRoot}`)
189
+ log(`Home: ${SWARMCLAW_HOME}`)
173
190
  log(`Data directory: ${DATA_DIR}`)
174
191
 
175
192
  if (opts.detach) {
@@ -248,6 +265,8 @@ function showStatus() {
248
265
  log(`Package: ${PKG_ROOT}`)
249
266
  log(`Home: ${SWARMCLAW_HOME}`)
250
267
  log(`Data: ${DATA_DIR}`)
268
+ log(`Workspace: ${WORKSPACE_DIR}`)
269
+ log(`Browser profiles: ${BROWSER_PROFILES_DIR}`)
251
270
  log(`WebSocket port: ${process.env.WS_PORT || '(PORT + 1)'}`)
252
271
 
253
272
  const serverJs = findStandaloneServer()
@@ -282,8 +301,7 @@ Options:
282
301
  console.log(help)
283
302
  }
284
303
 
285
- function main() {
286
- const args = process.argv.slice(3)
304
+ function main(args = process.argv.slice(3)) {
287
305
  let command = 'start'
288
306
  let forceBuild = false
289
307
  let detach = false
@@ -330,7 +348,17 @@ function main() {
330
348
  }
331
349
 
332
350
  if (needsBuild(forceBuild)) {
333
- runBuild()
351
+ if (!forceBuild) {
352
+ const installKind = isGitCheckout() ? 'checkout' : 'installed package'
353
+ log(`Standalone server bundle not found in this ${installKind}. Building locally...`)
354
+ }
355
+ try {
356
+ runBuild()
357
+ } catch (err) {
358
+ logError(`Build failed: ${err.message}`)
359
+ logError('Retry manually with: swarmclaw server --build')
360
+ process.exit(1)
361
+ }
334
362
  }
335
363
 
336
364
  startServer({ port, wsPort, host, detach })
@@ -342,10 +370,13 @@ if (require.main === module) {
342
370
 
343
371
  module.exports = {
344
372
  DATA_DIR,
373
+ BROWSER_PROFILES_DIR,
345
374
  PKG_ROOT,
346
375
  SWARMCLAW_HOME,
376
+ WORKSPACE_DIR,
347
377
  findStandaloneServer,
348
378
  getVersion,
379
+ isGitCheckout,
349
380
  main,
350
381
  needsBuild,
351
382
  resolveStandaloneBase,
package/bin/swarmclaw.js CHANGED
@@ -96,6 +96,19 @@ function normalizeLegacyCliEnv(env) {
96
96
  return nextEnv
97
97
  }
98
98
 
99
+ function printPackageVersion() {
100
+ const pkg = require('../package.json')
101
+ process.stdout.write(`${pkg.name || 'swarmclaw'} ${pkg.version || '0.0.0'}\n`)
102
+ }
103
+
104
+ function printVersionHelp() {
105
+ process.stdout.write(`
106
+ Usage: swarmclaw version
107
+
108
+ Show the installed SwarmClaw package version.
109
+ `.trim() + '\n')
110
+ }
111
+
99
112
  async function runMappedCli(argv) {
100
113
  const cliPath = path.join(__dirname, '..', 'src', 'cli', 'index.js')
101
114
  const cliModule = await import(cliPath)
@@ -106,25 +119,91 @@ async function runMappedCli(argv) {
106
119
  return runCli(argv)
107
120
  }
108
121
 
122
+ async function runHelp(argv) {
123
+ const [target, ...rest] = argv
124
+ if (!target) {
125
+ const code = await runMappedCli(['--help'])
126
+ process.exitCode = typeof code === 'number' ? code : 1
127
+ return
128
+ }
129
+
130
+ if (target === 'run' || target === 'start' || target === 'stop' || target === 'status' || target === 'server') {
131
+ require('./server-cmd.js').main(['--help'])
132
+ return
133
+ }
134
+ if (target === 'worker') {
135
+ require('./worker-cmd.js').main(['--help'])
136
+ return
137
+ }
138
+ if (target === 'doctor') {
139
+ require('./doctor-cmd.js').main(['--help'])
140
+ return
141
+ }
142
+ if (target === 'update') {
143
+ require('./update-cmd.js').main(['--help'])
144
+ return
145
+ }
146
+ if (target === 'version') {
147
+ printVersionHelp()
148
+ return
149
+ }
150
+
151
+ const forwarded = rest.includes('--help') || rest.includes('-h')
152
+ ? [target, ...rest]
153
+ : [target, ...rest, '--help']
154
+ const code = shouldUseLegacyTsCli(forwarded)
155
+ ? runLegacyTsCli(forwarded)
156
+ : await runMappedCli(forwarded)
157
+
158
+ process.exitCode = typeof code === 'number' ? code : 1
159
+ }
160
+
109
161
  async function main() {
110
162
  const argv = process.argv.slice(2)
111
163
  const top = argv[0]
112
164
 
113
165
  // Default to 'server' when invoked with no arguments.
114
166
  if (!top) {
115
- require('./server-cmd.js').main()
167
+ require('./server-cmd.js').main([])
168
+ return
169
+ }
170
+
171
+ if (top === '-v') {
172
+ printPackageVersion()
173
+ return
174
+ }
175
+
176
+ if (top === 'version' && argv.length === 1) {
177
+ printPackageVersion()
116
178
  return
117
179
  }
118
180
 
119
- // Route 'server', 'worker', and 'update' subcommands to CJS scripts (no TS dependency).
181
+ if (top === 'help') {
182
+ await runHelp(argv.slice(1))
183
+ return
184
+ }
185
+
186
+ // Route local lifecycle/maintenance commands to CJS scripts (no TS dependency).
120
187
  if (top === 'server') {
121
- require('./server-cmd.js').main()
188
+ require('./server-cmd.js').main(argv.slice(1))
189
+ return
190
+ }
191
+ if (top === 'run' || top === 'start') {
192
+ require('./server-cmd.js').main(argv.slice(1))
193
+ return
194
+ }
195
+ if (top === 'status' || top === 'stop') {
196
+ require('./server-cmd.js').main([top, ...argv.slice(1)])
122
197
  return
123
198
  }
124
199
  if (top === 'worker') {
125
200
  require('./worker-cmd.js').main()
126
201
  return
127
202
  }
203
+ if (top === 'doctor') {
204
+ require('./doctor-cmd.js').main(argv.slice(1))
205
+ return
206
+ }
128
207
  if (top === 'update') {
129
208
  require('./update-cmd.js').main()
130
209
  return
@@ -146,6 +225,7 @@ module.exports = {
146
225
  hasTsxRuntime,
147
226
  TS_CLI_ACTIONS,
148
227
  normalizeLegacyCliEnv,
228
+ printPackageVersion,
149
229
  supportsStripTypes,
150
230
  shouldUseLegacyTsCli,
151
231
  }
package/bin/update-cmd.js CHANGED
@@ -75,7 +75,6 @@ function runRegistrySelfUpdate(
75
75
  packageManager = resolveRegistryPackageManager(),
76
76
  execImpl = execFileSync,
77
77
  logger = { log, logError },
78
- rebuildImpl = execFileSync,
79
78
  ) {
80
79
  const update = getGlobalUpdateSpec(packageManager, PACKAGE_NAME)
81
80
  logger.log(`No git checkout detected. Updating the global ${PACKAGE_NAME} install via ${packageManager}...`)
@@ -92,15 +91,11 @@ function runRegistrySelfUpdate(
92
91
  return 1
93
92
  }
94
93
 
95
- const rebuildExitCode = rebuildStandaloneServer(rebuildImpl, logger)
96
- if (rebuildExitCode !== 0) return rebuildExitCode
97
-
98
94
  logger.log('Restart the server to apply changes: swarmclaw server stop && swarmclaw server start')
99
95
  return 0
100
96
  }
101
97
 
102
- function main() {
103
- const args = process.argv.slice(3)
98
+ function main(args = process.argv.slice(3)) {
104
99
  if (args.includes('-h') || args.includes('--help')) {
105
100
  console.log(`
106
101
  Usage: swarmclaw update
@@ -3,11 +3,10 @@
3
3
 
4
4
  const test = require('node:test')
5
5
  const assert = require('node:assert/strict')
6
- const path = require('node:path')
7
6
 
8
7
  const { runRegistrySelfUpdate } = require('./update-cmd.js')
9
8
 
10
- test('runRegistrySelfUpdate executes the manager-specific global update command and rebuilds the standalone server', () => {
9
+ test('runRegistrySelfUpdate executes the manager-specific global update command', () => {
11
10
  const messages = []
12
11
  const captured = []
13
12
 
@@ -20,9 +19,6 @@ test('runRegistrySelfUpdate executes the manager-specific global update command
20
19
  log: (message) => messages.push(`log:${message}`),
21
20
  logError: (message) => messages.push(`err:${message}`),
22
21
  },
23
- (command, args, options) => {
24
- captured.push({ command, args, options })
25
- },
26
22
  )
27
23
 
28
24
  assert.equal(exitCode, 0)
@@ -36,20 +32,9 @@ test('runRegistrySelfUpdate executes the manager-specific global update command
36
32
  timeout: 120_000,
37
33
  },
38
34
  },
39
- {
40
- command: process.execPath,
41
- args: [path.join(process.cwd(), 'bin', 'server-cmd.js'), '--build'],
42
- options: {
43
- cwd: process.cwd(),
44
- stdio: 'inherit',
45
- timeout: 600_000,
46
- },
47
- },
48
35
  ])
49
36
  assert.match(messages.join('\n'), /updating the global @swarmclawai\/swarmclaw install via pnpm/i)
50
37
  assert.match(messages.join('\n'), /global update complete via pnpm/i)
51
- assert.match(messages.join('\n'), /rebuilding the standalone server bundle/i)
52
- assert.match(messages.join('\n'), /standalone server bundle rebuilt/i)
53
38
  })
54
39
 
55
40
  test('runRegistrySelfUpdate reports a manual retry command when the registry update fails', () => {
@@ -70,23 +55,3 @@ test('runRegistrySelfUpdate reports a manual retry command when the registry upd
70
55
  assert.match(messages.join('\n'), /registry update failed: spawn bun ENOENT/i)
71
56
  assert.match(messages.join('\n'), /retry manually with: bun add -g @swarmclawai\/swarmclaw@latest/i)
72
57
  })
73
-
74
- test('runRegistrySelfUpdate reports a manual rebuild command when the rebuild step fails', () => {
75
- const messages = []
76
-
77
- const exitCode = runRegistrySelfUpdate(
78
- 'npm',
79
- () => {},
80
- {
81
- log: (message) => messages.push(`log:${message}`),
82
- logError: (message) => messages.push(`err:${message}`),
83
- },
84
- () => {
85
- throw new Error('build failed')
86
- },
87
- )
88
-
89
- assert.equal(exitCode, 1)
90
- assert.match(messages.join('\n'), /standalone rebuild failed: build failed/i)
91
- assert.match(messages.join('\n'), /retry manually with: swarmclaw server --build/i)
92
- })