@fyresmith/hive-server 2.2.0 → 2.3.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 -0
- package/cli/main.js +59 -2
- package/cli/tunnel.js +38 -0
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -127,8 +127,11 @@ Diagnostics:
|
|
|
127
127
|
```bash
|
|
128
128
|
hive doctor
|
|
129
129
|
hive status
|
|
130
|
+
hive update
|
|
130
131
|
```
|
|
131
132
|
|
|
133
|
+
`hive update` installs the latest npm release for the current package and then restarts the Hive OS service and cloudflared service when they are installed.
|
|
134
|
+
|
|
132
135
|
## Migration Notes
|
|
133
136
|
|
|
134
137
|
On first `hive setup`, if legacy `server/.env` exists and no `~/.hive/config.json` exists, setup will offer to import legacy env values.
|
package/cli/main.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { existsSync } from 'fs';
|
|
2
|
-
import { access } from 'fs/promises';
|
|
2
|
+
import { access, readFile } from 'fs/promises';
|
|
3
3
|
import { constants as fsConstants } from 'fs';
|
|
4
|
+
import { homedir } from 'os';
|
|
5
|
+
import { join } from 'path';
|
|
4
6
|
import process from 'process';
|
|
5
7
|
import { Command, CommanderError } from 'commander';
|
|
6
8
|
import prompts from 'prompts';
|
|
@@ -26,11 +28,12 @@ import {
|
|
|
26
28
|
writeEnvFile,
|
|
27
29
|
} from './env-file.js';
|
|
28
30
|
import { isPortAvailable, pathExists, validateDomain } from './checks.js';
|
|
29
|
-
import { run } from './exec.js';
|
|
31
|
+
import { run, runInherit } from './exec.js';
|
|
30
32
|
import {
|
|
31
33
|
cloudflaredServiceStatus,
|
|
32
34
|
installCloudflaredService,
|
|
33
35
|
runTunnelForeground,
|
|
36
|
+
restartCloudflaredServiceIfInstalled,
|
|
34
37
|
setupTunnel,
|
|
35
38
|
tunnelStatus,
|
|
36
39
|
getCloudflaredPath,
|
|
@@ -85,6 +88,54 @@ function resolveServiceConfig(config) {
|
|
|
85
88
|
};
|
|
86
89
|
}
|
|
87
90
|
|
|
91
|
+
async function loadPackageMeta() {
|
|
92
|
+
const raw = await readFile(new URL('../package.json', import.meta.url), 'utf-8');
|
|
93
|
+
const parsed = JSON.parse(raw);
|
|
94
|
+
const name = String(parsed?.name ?? '').trim();
|
|
95
|
+
const version = String(parsed?.version ?? '').trim() || 'unknown';
|
|
96
|
+
if (!name) {
|
|
97
|
+
throw new CliError('Could not resolve package name from package.json', EXIT.FAIL);
|
|
98
|
+
}
|
|
99
|
+
return { name, version };
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function isHiveServiceInstalled({ servicePlatform, serviceName }) {
|
|
103
|
+
if (servicePlatform === 'launchd') {
|
|
104
|
+
return existsSync(join(homedir(), 'Library', 'LaunchAgents', `${serviceName}.plist`));
|
|
105
|
+
}
|
|
106
|
+
return existsSync(`/etc/systemd/system/${serviceName}.service`);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
async function runUpdateFlow(options = {}) {
|
|
110
|
+
section('Hive Update');
|
|
111
|
+
|
|
112
|
+
const { config } = await resolveContext({});
|
|
113
|
+
const pkg = await loadPackageMeta();
|
|
114
|
+
const packageName = requiredOrFallback(options.package, pkg.name);
|
|
115
|
+
const hiveService = resolveServiceConfig(config);
|
|
116
|
+
|
|
117
|
+
info(`Current CLI version: ${pkg.version}`);
|
|
118
|
+
info(`Updating ${packageName} from npm (latest)`);
|
|
119
|
+
await runInherit('npm', ['install', '-g', `${packageName}@latest`]);
|
|
120
|
+
success(`Installed latest ${packageName}`);
|
|
121
|
+
|
|
122
|
+
if (isHiveServiceInstalled(hiveService)) {
|
|
123
|
+
info(`Restarting Hive service: ${hiveService.serviceName}`);
|
|
124
|
+
await restartHiveService(hiveService);
|
|
125
|
+
success('Hive service restarted');
|
|
126
|
+
} else {
|
|
127
|
+
info(`Hive service not installed: ${hiveService.serviceName}`);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
info('Restarting cloudflared service if installed');
|
|
131
|
+
const tunnelRestart = await restartCloudflaredServiceIfInstalled();
|
|
132
|
+
if (tunnelRestart.installed) {
|
|
133
|
+
success('cloudflared service restarted');
|
|
134
|
+
} else {
|
|
135
|
+
info('cloudflared service not installed');
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
88
139
|
async function loadValidatedEnv(envFile, { requireFile = true } = {}) {
|
|
89
140
|
if (requireFile && !existsSync(envFile)) {
|
|
90
141
|
throw new CliError(`Env file not found: ${envFile}. Run: hive env init`, EXIT.FAIL);
|
|
@@ -645,6 +696,12 @@ function registerRootCommands(program) {
|
|
|
645
696
|
.option('--yes', 'non-interactive mode', false)
|
|
646
697
|
.action(runSetupWizard);
|
|
647
698
|
|
|
699
|
+
program
|
|
700
|
+
.command('update')
|
|
701
|
+
.description('Update Hive from npm and restart installed services')
|
|
702
|
+
.option('--package <name>', 'npm package override')
|
|
703
|
+
.action(runUpdateFlow);
|
|
704
|
+
|
|
648
705
|
program
|
|
649
706
|
.command('doctor')
|
|
650
707
|
.description('Run prerequisite and configuration checks')
|
package/cli/tunnel.js
CHANGED
|
@@ -160,6 +160,44 @@ export async function installCloudflaredService() {
|
|
|
160
160
|
await runInherit('sudo', ['cloudflared', 'service', 'install']);
|
|
161
161
|
}
|
|
162
162
|
|
|
163
|
+
function isMissingCloudflaredService(output) {
|
|
164
|
+
const text = String(output ?? '').toLowerCase();
|
|
165
|
+
return (
|
|
166
|
+
text.includes('could not find service')
|
|
167
|
+
|| text.includes('service does not exist')
|
|
168
|
+
|| text.includes('unit cloudflared.service not found')
|
|
169
|
+
|| text.includes('could not be found')
|
|
170
|
+
|| text.includes('not loaded')
|
|
171
|
+
|| text.includes('no such file or directory')
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
export async function restartCloudflaredServiceIfInstalled() {
|
|
176
|
+
const platform = detectPlatform();
|
|
177
|
+
|
|
178
|
+
try {
|
|
179
|
+
if (platform === 'darwin') {
|
|
180
|
+
await runInherit('sudo', ['launchctl', 'kickstart', '-k', 'system/com.cloudflare.cloudflared']);
|
|
181
|
+
} else {
|
|
182
|
+
await runInherit('sudo', ['systemctl', 'restart', 'cloudflared']);
|
|
183
|
+
}
|
|
184
|
+
return { installed: true, restarted: true };
|
|
185
|
+
} catch (err) {
|
|
186
|
+
const output = [
|
|
187
|
+
err?.stdout,
|
|
188
|
+
err?.stderr,
|
|
189
|
+
err?.shortMessage,
|
|
190
|
+
err?.message,
|
|
191
|
+
]
|
|
192
|
+
.filter(Boolean)
|
|
193
|
+
.join('\n');
|
|
194
|
+
if (isMissingCloudflaredService(output)) {
|
|
195
|
+
return { installed: false, restarted: false };
|
|
196
|
+
}
|
|
197
|
+
throw err;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
163
201
|
export async function cloudflaredServiceStatus() {
|
|
164
202
|
const platform = detectPlatform();
|
|
165
203
|
if (platform === 'darwin') {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fyresmith/hive-server",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.3.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Collaborative Obsidian vault server",
|
|
6
6
|
"main": "index.js",
|
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
"test": "npm run verify"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
+
"@fyresmith/hive-server": "^2.2.0",
|
|
34
35
|
"chalk": "^5.6.2",
|
|
35
36
|
"chokidar": "^3.6.0",
|
|
36
37
|
"commander": "^13.1.0",
|