@alexberardi/jarvis-admin 0.1.49 → 0.1.53
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/package.json +1 -1
- package/public/assets/index-BSTio8c-.css +1 -0
- package/public/assets/index-DWQc4gfz.js +18 -0
- package/public/index.html +2 -2
- package/server/dist/app.d.ts.map +1 -1
- package/server/dist/app.js +2 -0
- package/server/dist/app.js.map +1 -1
- package/server/dist/data/service-registry.json +5 -2
- package/server/dist/routes/install.d.ts.map +1 -1
- package/server/dist/routes/install.js +40 -19
- package/server/dist/routes/install.js.map +1 -1
- package/server/dist/routes/native-services.d.ts +3 -0
- package/server/dist/routes/native-services.d.ts.map +1 -0
- package/server/dist/routes/native-services.js +318 -0
- package/server/dist/routes/native-services.js.map +1 -0
- package/server/dist/routes/services.d.ts.map +1 -1
- package/server/dist/routes/services.js +63 -0
- package/server/dist/routes/services.js.map +1 -1
- package/server/dist/services/generators/compose-generator.d.ts +8 -1
- package/server/dist/services/generators/compose-generator.d.ts.map +1 -1
- package/server/dist/services/generators/compose-generator.js +33 -10
- package/server/dist/services/generators/compose-generator.js.map +1 -1
- package/server/dist/services/generators/env-generator.d.ts.map +1 -1
- package/server/dist/services/generators/env-generator.js +19 -0
- package/server/dist/services/generators/env-generator.js.map +1 -1
- package/server/dist/services/host-platform.d.ts +5 -0
- package/server/dist/services/host-platform.d.ts.map +1 -0
- package/server/dist/services/host-platform.js +55 -0
- package/server/dist/services/host-platform.js.map +1 -0
- package/server/dist/services/upgrade/compose-upgrader.d.ts +1 -0
- package/server/dist/services/upgrade/compose-upgrader.d.ts.map +1 -1
- package/server/dist/services/upgrade/compose-upgrader.js +3 -0
- package/server/dist/services/upgrade/compose-upgrader.js.map +1 -1
- package/server/dist/services/upgrade/state-reconstructor.d.ts.map +1 -1
- package/server/dist/services/upgrade/state-reconstructor.js +14 -2
- package/server/dist/services/upgrade/state-reconstructor.js.map +1 -1
- package/server/dist/types/service-registry.d.ts +7 -0
- package/server/dist/types/service-registry.d.ts.map +1 -1
- package/server/dist/types/wizard.d.ts +9 -0
- package/server/dist/types/wizard.d.ts.map +1 -1
- package/server/node_modules/cpu-features/build/Makefile +2 -2
- package/server/node_modules/cpu-features/build/Release/.deps/Release/obj.target/cpu_features/deps/cpu_features/src/filesystem.o.d +1 -1
- package/server/node_modules/cpu-features/build/Release/.deps/Release/obj.target/cpu_features/deps/cpu_features/src/impl_aarch64_linux_or_android.o.d +1 -1
- package/server/node_modules/cpu-features/build/Release/.deps/Release/obj.target/cpu_features/deps/cpu_features/src/impl_aarch64_macos_or_iphone.o.d +1 -1
- package/server/node_modules/cpu-features/build/Release/.deps/Release/obj.target/cpu_features/deps/cpu_features/src/impl_aarch64_windows.o.d +1 -1
- package/server/node_modules/cpu-features/build/Release/.deps/Release/obj.target/cpu_features/deps/cpu_features/src/impl_arm_linux_or_android.o.d +1 -1
- package/server/node_modules/cpu-features/build/Release/.deps/Release/obj.target/cpu_features/deps/cpu_features/src/impl_mips_linux_or_android.o.d +1 -1
- package/server/node_modules/cpu-features/build/Release/.deps/Release/obj.target/cpu_features/deps/cpu_features/src/impl_ppc_linux.o.d +1 -1
- package/server/node_modules/cpu-features/build/Release/.deps/Release/obj.target/cpu_features/deps/cpu_features/src/impl_x86_freebsd.o.d +1 -1
- package/server/node_modules/cpu-features/build/Release/.deps/Release/obj.target/cpu_features/deps/cpu_features/src/impl_x86_linux_or_android.o.d +1 -1
- package/server/node_modules/cpu-features/build/Release/.deps/Release/obj.target/cpu_features/deps/cpu_features/src/impl_x86_macos.o.d +1 -1
- package/server/node_modules/cpu-features/build/Release/.deps/Release/obj.target/cpu_features/deps/cpu_features/src/impl_x86_windows.o.d +1 -1
- package/server/node_modules/cpu-features/build/Release/.deps/Release/obj.target/cpu_features/deps/cpu_features/src/stack_line_reader.o.d +1 -1
- package/server/node_modules/cpu-features/build/Release/.deps/Release/obj.target/cpu_features/deps/cpu_features/src/string_view.o.d +1 -1
- package/server/node_modules/cpu-features/build/Release/.deps/Release/obj.target/cpufeatures/src/binding.o.d +135 -135
- package/server/node_modules/cpu-features/build/cpufeatures.target.mk +14 -14
- package/server/node_modules/cpu-features/build/deps/cpu_features/cpu_features.target.mk +14 -14
- package/server/node_modules/ssh2/lib/protocol/crypto/build/Makefile +2 -2
- package/server/node_modules/ssh2/lib/protocol/crypto/build/Release/.deps/Release/obj.target/sshcrypto/src/binding.o.d +227 -227
- package/server/node_modules/ssh2/lib/protocol/crypto/build/Release/obj.target/sshcrypto/src/binding.o +0 -0
- package/server/node_modules/ssh2/lib/protocol/crypto/build/Release/obj.target/sshcrypto.node +0 -0
- package/server/node_modules/ssh2/lib/protocol/crypto/build/Release/sshcrypto.node +0 -0
- package/server/node_modules/ssh2/lib/protocol/crypto/build/sshcrypto.target.mk +14 -14
- package/server/src/data/service-registry.json +5 -2
- package/public/assets/index-Be27jKL8.js +0 -18
- package/public/assets/index-Bz2OBqE1.css +0 -1
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
// macOS-only routes that manage services running as user LaunchAgents instead
|
|
2
|
+
// of Docker containers. The corresponding docker-compose services are excluded
|
|
3
|
+
// by compose-generator when the user opts in via WizardState.nativeServices.
|
|
4
|
+
//
|
|
5
|
+
// Each managed service ships its own `deploy-launchd.sh` + plist template in
|
|
6
|
+
// its own repo; this module orchestrates them. Source is taken from
|
|
7
|
+
// `JARVIS_ROOT/<service-id>` if present (dev), otherwise cloned to
|
|
8
|
+
// `~/.jarvis/native/<service-id>` from GitHub.
|
|
9
|
+
import { existsSync, mkdirSync, readFileSync, unlinkSync, statSync } from 'node:fs';
|
|
10
|
+
import { spawn, execSync } from 'node:child_process';
|
|
11
|
+
import { homedir } from 'node:os';
|
|
12
|
+
import { join } from 'node:path';
|
|
13
|
+
import { requireSuperuser } from '../middleware/auth.js';
|
|
14
|
+
import { parseRegistry } from '../services/generators/service-registry.js';
|
|
15
|
+
import registryData from '../data/service-registry.json' with { type: 'json' };
|
|
16
|
+
import { getComposePath } from '../services/compose-path.js';
|
|
17
|
+
import { getHostPlatform } from '../services/host-platform.js';
|
|
18
|
+
const GITHUB_ORG = 'alexberardi';
|
|
19
|
+
const NATIVE_ROOT = join(homedir(), '.jarvis', 'native');
|
|
20
|
+
/**
|
|
21
|
+
* Map a service ID → the launchd label its deploy-launchd.sh installs.
|
|
22
|
+
* llm-proxy uses the legacy label (com.jarvis.llm-proxy, not -api) so
|
|
23
|
+
* existing installs aren't orphaned.
|
|
24
|
+
*/
|
|
25
|
+
function launchdLabel(serviceId) {
|
|
26
|
+
if (serviceId === 'jarvis-llm-proxy-api')
|
|
27
|
+
return 'com.jarvis.llm-proxy';
|
|
28
|
+
return `com.jarvis.${serviceId.replace(/^jarvis-/, '')}`;
|
|
29
|
+
}
|
|
30
|
+
/** Returns the directory with a checkout of the service repo, cloning if missing. */
|
|
31
|
+
function resolveSourceDir(serviceId) {
|
|
32
|
+
const dev = process.env.JARVIS_ROOT
|
|
33
|
+
? join(process.env.JARVIS_ROOT, serviceId)
|
|
34
|
+
: null;
|
|
35
|
+
if (dev && existsSync(join(dev, 'deploy-launchd.sh')))
|
|
36
|
+
return dev;
|
|
37
|
+
const target = join(NATIVE_ROOT, serviceId);
|
|
38
|
+
if (existsSync(join(target, 'deploy-launchd.sh')))
|
|
39
|
+
return target;
|
|
40
|
+
return target; // doesn't exist yet — caller will clone
|
|
41
|
+
}
|
|
42
|
+
function logDir(serviceId) {
|
|
43
|
+
// The plists in each service write to ~/Library/Logs/<dirname>; mirror their
|
|
44
|
+
// naming so the log endpoint can find them. llm-proxy uses a shortened dir.
|
|
45
|
+
if (serviceId === 'jarvis-llm-proxy-api') {
|
|
46
|
+
return join(homedir(), 'Library', 'Logs', 'jarvis-llm-proxy');
|
|
47
|
+
}
|
|
48
|
+
return join(homedir(), 'Library', 'Logs', serviceId);
|
|
49
|
+
}
|
|
50
|
+
function plistPath(label) {
|
|
51
|
+
return join(homedir(), 'Library', 'LaunchAgents', `${label}.plist`);
|
|
52
|
+
}
|
|
53
|
+
/** Returns true when launchctl reports `state = running` for the label. */
|
|
54
|
+
function isRunning(label) {
|
|
55
|
+
try {
|
|
56
|
+
const uid = execSync('id -u', { encoding: 'utf-8' }).trim();
|
|
57
|
+
const output = execSync(`launchctl print gui/${uid}/${label} 2>/dev/null`, {
|
|
58
|
+
encoding: 'utf-8',
|
|
59
|
+
timeout: 3000,
|
|
60
|
+
});
|
|
61
|
+
const stateMatch = output.match(/state\s*=\s*(\w+)/);
|
|
62
|
+
const pidMatch = output.match(/pid\s*=\s*(\d+)/);
|
|
63
|
+
const running = stateMatch?.[1] === 'running';
|
|
64
|
+
return { running, pid: pidMatch ? parseInt(pidMatch[1], 10) : undefined };
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
return { running: false };
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
function loadEnvFile(composePath) {
|
|
71
|
+
const envPath = join(composePath, '.env');
|
|
72
|
+
if (!existsSync(envPath))
|
|
73
|
+
return {};
|
|
74
|
+
const content = readFileSync(envPath, 'utf-8');
|
|
75
|
+
const vars = {};
|
|
76
|
+
for (const line of content.split('\n')) {
|
|
77
|
+
const trimmed = line.trim();
|
|
78
|
+
if (!trimmed || trimmed.startsWith('#'))
|
|
79
|
+
continue;
|
|
80
|
+
const eq = trimmed.indexOf('=');
|
|
81
|
+
if (eq === -1)
|
|
82
|
+
continue;
|
|
83
|
+
vars[trimmed.slice(0, eq)] = trimmed.slice(eq + 1);
|
|
84
|
+
}
|
|
85
|
+
return vars;
|
|
86
|
+
}
|
|
87
|
+
function resolvePort(serviceId, svc, composePath) {
|
|
88
|
+
const env = loadEnvFile(composePath);
|
|
89
|
+
const portVarMap = {
|
|
90
|
+
'jarvis-llm-proxy-api': 'LLM_PROXY_API_PORT',
|
|
91
|
+
'jarvis-whisper-api': 'WHISPER_API_PORT',
|
|
92
|
+
'jarvis-tts': 'TTS_PORT',
|
|
93
|
+
};
|
|
94
|
+
const portVar = portVarMap[serviceId];
|
|
95
|
+
if (portVar && env[portVar]) {
|
|
96
|
+
const p = parseInt(env[portVar], 10);
|
|
97
|
+
if (!Number.isNaN(p))
|
|
98
|
+
return p;
|
|
99
|
+
}
|
|
100
|
+
return svc.port;
|
|
101
|
+
}
|
|
102
|
+
function nativeCapableServices(registry) {
|
|
103
|
+
return registry.services.filter((s) => s.nativeCapable);
|
|
104
|
+
}
|
|
105
|
+
export async function nativeServicesRoutes(app) {
|
|
106
|
+
const registry = parseRegistry(registryData);
|
|
107
|
+
// Auth policy here mirrors /api/install/*: the wizard runs install BEFORE
|
|
108
|
+
// there is a superuser account, so install + status are open (same trust
|
|
109
|
+
// model as the rest of the bootstrap). Post-install lifecycle ops
|
|
110
|
+
// (start/stop/uninstall) require superuser since they can disable services
|
|
111
|
+
// running on a live install.
|
|
112
|
+
/** Catalog + status for every native-capable service. */
|
|
113
|
+
app.get('/', async (_request, reply) => {
|
|
114
|
+
if (getHostPlatform() !== 'darwin') {
|
|
115
|
+
return reply.send({ supported: false, services: [] });
|
|
116
|
+
}
|
|
117
|
+
const services = nativeCapableServices(registry).map((svc) => {
|
|
118
|
+
const label = launchdLabel(svc.id);
|
|
119
|
+
const installed = existsSync(plistPath(label));
|
|
120
|
+
const { running, pid } = installed ? isRunning(label) : { running: false };
|
|
121
|
+
const sourceDir = resolveSourceDir(svc.id);
|
|
122
|
+
const sourceExists = existsSync(join(sourceDir, 'deploy-launchd.sh'));
|
|
123
|
+
const logs = logDir(svc.id);
|
|
124
|
+
const status = {
|
|
125
|
+
serviceId: svc.id,
|
|
126
|
+
label,
|
|
127
|
+
installed,
|
|
128
|
+
running,
|
|
129
|
+
pid,
|
|
130
|
+
sourceDir: sourceExists ? sourceDir : undefined,
|
|
131
|
+
port: resolvePort(svc.id, svc, getComposePath()),
|
|
132
|
+
logs: {
|
|
133
|
+
stdout: join(logs, 'out.log'),
|
|
134
|
+
stderr: join(logs, 'err.log'),
|
|
135
|
+
},
|
|
136
|
+
};
|
|
137
|
+
return { ...svc, status };
|
|
138
|
+
});
|
|
139
|
+
return reply.send({ supported: true, services });
|
|
140
|
+
});
|
|
141
|
+
/**
|
|
142
|
+
* SSE: install (clone if needed) + run deploy-launchd.sh for one service.
|
|
143
|
+
* Streams stdout/stderr of the deploy script so the wizard can show progress.
|
|
144
|
+
*
|
|
145
|
+
* GET (not POST) because EventSource is GET-only, matching /api/install/start.
|
|
146
|
+
*/
|
|
147
|
+
app.get('/:id/install', async (request, reply) => {
|
|
148
|
+
if (getHostPlatform() !== 'darwin') {
|
|
149
|
+
return reply.code(400).send({ error: 'Native services are macOS-only' });
|
|
150
|
+
}
|
|
151
|
+
const { id } = request.params;
|
|
152
|
+
const svc = registry.services.find((s) => s.id === id);
|
|
153
|
+
if (!svc)
|
|
154
|
+
return reply.code(404).send({ error: `Unknown service: ${id}` });
|
|
155
|
+
if (!svc.nativeCapable) {
|
|
156
|
+
return reply.code(400).send({ error: `${id} does not support native install` });
|
|
157
|
+
}
|
|
158
|
+
reply.raw.writeHead(200, {
|
|
159
|
+
'Content-Type': 'text/event-stream',
|
|
160
|
+
'Cache-Control': 'no-cache',
|
|
161
|
+
Connection: 'keep-alive',
|
|
162
|
+
'X-Accel-Buffering': 'no',
|
|
163
|
+
});
|
|
164
|
+
const emit = (data) => {
|
|
165
|
+
try {
|
|
166
|
+
reply.raw.write(`data: ${JSON.stringify(data)}\n\n`);
|
|
167
|
+
}
|
|
168
|
+
catch {
|
|
169
|
+
// Client disconnected mid-stream — let the child finish anyway.
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
const composePath = getComposePath();
|
|
173
|
+
const envFilePath = join(composePath, '.env');
|
|
174
|
+
const port = resolvePort(id, svc, composePath);
|
|
175
|
+
const sourceDir = resolveSourceDir(id);
|
|
176
|
+
try {
|
|
177
|
+
// Phase 1: ensure source is on disk
|
|
178
|
+
if (!existsSync(join(sourceDir, 'deploy-launchd.sh'))) {
|
|
179
|
+
mkdirSync(NATIVE_ROOT, { recursive: true });
|
|
180
|
+
emit({ phase: 'clone', message: `Cloning ${id} into ${sourceDir}` });
|
|
181
|
+
await runStreaming('git', ['clone', '--depth', '1', `https://github.com/${GITHUB_ORG}/${id}.git`, sourceDir], { cwd: NATIVE_ROOT }, emit);
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
emit({ phase: 'source', message: `Using existing checkout at ${sourceDir}` });
|
|
185
|
+
}
|
|
186
|
+
if (!existsSync(join(sourceDir, 'deploy-launchd.sh'))) {
|
|
187
|
+
throw new Error(`deploy-launchd.sh missing in ${sourceDir} after clone — repo layout may be wrong`);
|
|
188
|
+
}
|
|
189
|
+
// Phase 2: deploy launchagent. The script handles plist materialization +
|
|
190
|
+
// launchctl bootstrap; first run also kicks off venv creation + pip
|
|
191
|
+
// install via run-prod-native.sh, which can take minutes.
|
|
192
|
+
emit({ phase: 'launchd', message: `Deploying launchd agent on port ${port}` });
|
|
193
|
+
await runStreaming('bash', [join(sourceDir, 'deploy-launchd.sh')], {
|
|
194
|
+
cwd: sourceDir,
|
|
195
|
+
env: {
|
|
196
|
+
...process.env,
|
|
197
|
+
ENV_FILE_PATH: envFilePath,
|
|
198
|
+
[portEnvVarFor(id)]: String(port),
|
|
199
|
+
},
|
|
200
|
+
}, emit);
|
|
201
|
+
const label = launchdLabel(id);
|
|
202
|
+
emit({ phase: 'done', label, sourceDir, port, message: 'LaunchAgent ready', done: true, code: 0 });
|
|
203
|
+
}
|
|
204
|
+
catch (err) {
|
|
205
|
+
emit({ phase: 'error', message: err instanceof Error ? err.message : String(err), done: true, code: 1 });
|
|
206
|
+
}
|
|
207
|
+
reply.raw.end();
|
|
208
|
+
});
|
|
209
|
+
/** Restart (kickstart -k) — also used for "start". */
|
|
210
|
+
app.post('/:id/restart', { preHandler: requireSuperuser }, async (request, reply) => {
|
|
211
|
+
if (getHostPlatform() !== 'darwin')
|
|
212
|
+
return reply.code(400).send({ error: 'macOS only' });
|
|
213
|
+
const label = launchdLabel(request.params.id);
|
|
214
|
+
if (!existsSync(plistPath(label))) {
|
|
215
|
+
return reply.code(404).send({ error: `${label} not installed` });
|
|
216
|
+
}
|
|
217
|
+
try {
|
|
218
|
+
const uid = execSync('id -u', { encoding: 'utf-8' }).trim();
|
|
219
|
+
execSync(`launchctl kickstart -k gui/${uid}/${label}`, { timeout: 5000 });
|
|
220
|
+
return reply.send({ ok: true, label });
|
|
221
|
+
}
|
|
222
|
+
catch (err) {
|
|
223
|
+
return reply.code(500).send({
|
|
224
|
+
error: err instanceof Error ? err.message : String(err),
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
});
|
|
228
|
+
/** Stop (bootout) — leaves the plist in place so the user can re-enable later. */
|
|
229
|
+
app.post('/:id/stop', { preHandler: requireSuperuser }, async (request, reply) => {
|
|
230
|
+
if (getHostPlatform() !== 'darwin')
|
|
231
|
+
return reply.code(400).send({ error: 'macOS only' });
|
|
232
|
+
const label = launchdLabel(request.params.id);
|
|
233
|
+
try {
|
|
234
|
+
const uid = execSync('id -u', { encoding: 'utf-8' }).trim();
|
|
235
|
+
execSync(`launchctl bootout gui/${uid}/${label} 2>/dev/null || true`, { timeout: 5000 });
|
|
236
|
+
return reply.send({ ok: true, label });
|
|
237
|
+
}
|
|
238
|
+
catch (err) {
|
|
239
|
+
return reply.code(500).send({
|
|
240
|
+
error: err instanceof Error ? err.message : String(err),
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
});
|
|
244
|
+
/** Uninstall: stop AND remove the plist file. */
|
|
245
|
+
app.post('/:id/uninstall', { preHandler: requireSuperuser }, async (request, reply) => {
|
|
246
|
+
if (getHostPlatform() !== 'darwin')
|
|
247
|
+
return reply.code(400).send({ error: 'macOS only' });
|
|
248
|
+
const label = launchdLabel(request.params.id);
|
|
249
|
+
const plist = plistPath(label);
|
|
250
|
+
try {
|
|
251
|
+
const uid = execSync('id -u', { encoding: 'utf-8' }).trim();
|
|
252
|
+
execSync(`launchctl bootout gui/${uid}/${label} 2>/dev/null || true`, { timeout: 5000 });
|
|
253
|
+
if (existsSync(plist)) {
|
|
254
|
+
unlinkSync(plist);
|
|
255
|
+
}
|
|
256
|
+
return reply.send({ ok: true, label, removedPlist: plist });
|
|
257
|
+
}
|
|
258
|
+
catch (err) {
|
|
259
|
+
return reply.code(500).send({
|
|
260
|
+
error: err instanceof Error ? err.message : String(err),
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
});
|
|
264
|
+
/**
|
|
265
|
+
* Tail the last N lines of stdout or stderr. Reads from disk rather than
|
|
266
|
+
* proxying launchctl — the plist's StandardOutPath / StandardErrorPath
|
|
267
|
+
* point at predictable files.
|
|
268
|
+
*/
|
|
269
|
+
app.get('/:id/logs', { preHandler: requireSuperuser }, async (request, reply) => {
|
|
270
|
+
if (getHostPlatform() !== 'darwin')
|
|
271
|
+
return reply.code(400).send({ error: 'macOS only' });
|
|
272
|
+
const { id } = request.params;
|
|
273
|
+
const { stream = 'stderr', lines = '200' } = request.query;
|
|
274
|
+
const dir = logDir(id);
|
|
275
|
+
const file = join(dir, stream === 'stdout' ? 'out.log' : 'err.log');
|
|
276
|
+
if (!existsSync(file)) {
|
|
277
|
+
return reply.send({ file, content: '', size: 0 });
|
|
278
|
+
}
|
|
279
|
+
try {
|
|
280
|
+
const size = statSync(file).size;
|
|
281
|
+
const wanted = Math.min(parseInt(lines, 10) || 200, 5000);
|
|
282
|
+
// tail -n via shell — avoids loading huge log files into memory.
|
|
283
|
+
const content = execSync(`tail -n ${wanted} "${file}"`, { encoding: 'utf-8', timeout: 5000 });
|
|
284
|
+
return reply.send({ file, content, size });
|
|
285
|
+
}
|
|
286
|
+
catch (err) {
|
|
287
|
+
return reply.code(500).send({
|
|
288
|
+
error: err instanceof Error ? err.message : String(err),
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
/** Env var name the deploy-launchd scripts read for the listener port. */
|
|
294
|
+
function portEnvVarFor(serviceId) {
|
|
295
|
+
if (serviceId === 'jarvis-llm-proxy-api')
|
|
296
|
+
return 'LLM_PROXY_PORT';
|
|
297
|
+
if (serviceId === 'jarvis-whisper-api')
|
|
298
|
+
return 'WHISPER_PORT';
|
|
299
|
+
if (serviceId === 'jarvis-tts')
|
|
300
|
+
return 'TTS_PORT';
|
|
301
|
+
return 'PORT';
|
|
302
|
+
}
|
|
303
|
+
/** Run a child process and emit its stdout/stderr through the SSE emitter. */
|
|
304
|
+
async function runStreaming(cmd, args, opts, emit) {
|
|
305
|
+
return new Promise((resolve, reject) => {
|
|
306
|
+
const child = spawn(cmd, args, { cwd: opts.cwd, env: opts.env });
|
|
307
|
+
child.stdout.on('data', (buf) => emit({ stream: 'stdout', text: buf.toString() }));
|
|
308
|
+
child.stderr.on('data', (buf) => emit({ stream: 'stderr', text: buf.toString() }));
|
|
309
|
+
child.on('error', reject);
|
|
310
|
+
child.on('close', (code) => {
|
|
311
|
+
if (code === 0)
|
|
312
|
+
resolve();
|
|
313
|
+
else
|
|
314
|
+
reject(new Error(`${cmd} exited with code ${code}`));
|
|
315
|
+
});
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
//# sourceMappingURL=native-services.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"native-services.js","sourceRoot":"","sources":["../../src/routes/native-services.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"services.d.ts","sourceRoot":"","sources":["../../src/routes/services.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"services.d.ts","sourceRoot":"","sources":["../../src/routes/services.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AA2C9C,wBAAsB,cAAc,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAmHxE"}
|
|
@@ -1,5 +1,44 @@
|
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
1
3
|
import { requireSuperuser } from '../middleware/auth.js';
|
|
2
4
|
import { proxyRequest } from '../services/proxy.js';
|
|
5
|
+
import { injectAppKeys } from '../services/orchestrator.js';
|
|
6
|
+
import { getComposePath } from '../services/compose-path.js';
|
|
7
|
+
/**
|
|
8
|
+
* Persist a newly-rotated app key to the central composePath/.env so the
|
|
9
|
+
* service container picks it up after restart. Mirrors the .env write
|
|
10
|
+
* that ``registerServices`` already does at the end of the register
|
|
11
|
+
* flow, just scoped to a single service.
|
|
12
|
+
*
|
|
13
|
+
* Returns true if the .env file existed and was successfully written.
|
|
14
|
+
* Returns false (and logs at warn level) on any failure — callers
|
|
15
|
+
* surface this via ``env_written`` in the response so the UI can tell
|
|
16
|
+
* the user whether they still have manual work to do.
|
|
17
|
+
*
|
|
18
|
+
* Note: this targets the central ``composePath/.env`` convention with
|
|
19
|
+
* prefixed key names (``JARVIS_APP_KEY_LOGS``) used by production
|
|
20
|
+
* installs. Dev environments using per-service .env files with simple
|
|
21
|
+
* ``JARVIS_APP_KEY`` names need a separate update (out of scope for
|
|
22
|
+
* this fix — see May-2026 beta debugging notes).
|
|
23
|
+
*/
|
|
24
|
+
function persistRotatedKey(serviceName, appKey) {
|
|
25
|
+
const composePath = getComposePath();
|
|
26
|
+
const envFile = join(composePath, '.env');
|
|
27
|
+
if (!existsSync(envFile))
|
|
28
|
+
return false;
|
|
29
|
+
try {
|
|
30
|
+
const envContent = readFileSync(envFile, 'utf-8');
|
|
31
|
+
const { content: updatedContent } = injectAppKeys(envContent, {
|
|
32
|
+
[serviceName]: { appId: serviceName, appKey },
|
|
33
|
+
});
|
|
34
|
+
writeFileSync(envFile, updatedContent);
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
catch (err) {
|
|
38
|
+
console.warn(`[services] Failed to write rotated key for ${serviceName} to ${envFile}:`, err instanceof Error ? err.message : String(err));
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
3
42
|
export async function servicesRoutes(app) {
|
|
4
43
|
app.addHook('preHandler', requireSuperuser);
|
|
5
44
|
app.get('/registry', async (request, reply) => {
|
|
@@ -32,6 +71,30 @@ export async function servicesRoutes(app) {
|
|
|
32
71
|
body: request.body,
|
|
33
72
|
timeout: 10_000,
|
|
34
73
|
});
|
|
74
|
+
// If rotation succeeded, write the new plaintext to the central
|
|
75
|
+
// composePath/.env. Without this step, the UI used to return the
|
|
76
|
+
// new key in the modal but nothing wrote it anywhere — operators
|
|
77
|
+
// had to copy it by hand from the modal, and one missed copy left
|
|
78
|
+
// the .env stuck on its placeholder indefinitely. (May-2026 beta
|
|
79
|
+
// debugging: dev jarvis-logs never got off ``your-jarvis-logs-app-key``
|
|
80
|
+
// because every rotate flow was relying on manual transcription.)
|
|
81
|
+
//
|
|
82
|
+
// We augment the response with ``env_written`` so the UI can tell
|
|
83
|
+
// the user whether they still need to update .env manually.
|
|
84
|
+
if (result.status === 200 && result.data && typeof result.data === 'object') {
|
|
85
|
+
const payload = result.data;
|
|
86
|
+
if (payload.service_name && payload.app_key) {
|
|
87
|
+
const wrote = persistRotatedKey(payload.service_name, payload.app_key);
|
|
88
|
+
// Preserve any env_written the upstream config-service may have
|
|
89
|
+
// already set (it has its own --base-path branch); otherwise
|
|
90
|
+
// surface ours.
|
|
91
|
+
if (payload.env_written !== true) {
|
|
92
|
+
payload.env_written = wrote;
|
|
93
|
+
}
|
|
94
|
+
reply.code(result.status).send(payload);
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
35
98
|
reply.code(result.status).send(result.data);
|
|
36
99
|
});
|
|
37
100
|
app.post('/probe', async (request, reply) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"services.js","sourceRoot":"","sources":["../../src/routes/services.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"services.js","sourceRoot":"","sources":["../../src/routes/services.ts"],"names":[],"mappings":"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"}
|
|
@@ -7,7 +7,14 @@ import type { ServiceRegistry, ServiceDefinition } from '../../types/service-reg
|
|
|
7
7
|
export declare function getAllEnabledServices(state: WizardState, registry: ServiceRegistry): ServiceDefinition[];
|
|
8
8
|
/**
|
|
9
9
|
* Returns services to include in docker-compose.
|
|
10
|
-
*
|
|
10
|
+
*
|
|
11
|
+
* On macOS the filter has two layers:
|
|
12
|
+
* 1. GPU-required services without a `cpuFallback` image (e.g. legacy
|
|
13
|
+
* llm-proxy) are always excluded — Docker on Mac can't reach the GPU,
|
|
14
|
+
* so the container would be useless.
|
|
15
|
+
* 2. Any service the user explicitly opted into native mode (via the
|
|
16
|
+
* wizard's native-services step → WizardState.nativeServices) is also
|
|
17
|
+
* excluded; it'll be installed as a LaunchAgent instead.
|
|
11
18
|
*/
|
|
12
19
|
export declare function getComposeServices(state: WizardState, registry: ServiceRegistry): ServiceDefinition[];
|
|
13
20
|
/** Worker container IDs emitted alongside the given services in the compose file. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compose-generator.d.ts","sourceRoot":"","sources":["../../../src/services/generators/compose-generator.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AACxD,OAAO,KAAK,EACV,eAAe,EACf,iBAAiB,EAGlB,MAAM,iCAAiC,CAAA;AASxC;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,WAAW,EAClB,QAAQ,EAAE,eAAe,GACxB,iBAAiB,EAAE,CASrB;AAED
|
|
1
|
+
{"version":3,"file":"compose-generator.d.ts","sourceRoot":"","sources":["../../../src/services/generators/compose-generator.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AACxD,OAAO,KAAK,EACV,eAAe,EACf,iBAAiB,EAGlB,MAAM,iCAAiC,CAAA;AASxC;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,WAAW,EAClB,QAAQ,EAAE,eAAe,GACxB,iBAAiB,EAAE,CASrB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,WAAW,EAClB,QAAQ,EAAE,eAAe,GACxB,iBAAiB,EAAE,CAWrB;AAiBD,qFAAqF;AACrF,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,iBAAiB,EAAE,GAAG,MAAM,EAAE,CAE3E;AA0BD,wBAAgB,eAAe,CAAC,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,eAAe,GAAG,MAAM,CA+DrF"}
|
|
@@ -12,14 +12,26 @@ export function getAllEnabledServices(state, registry) {
|
|
|
12
12
|
}
|
|
13
13
|
/**
|
|
14
14
|
* Returns services to include in docker-compose.
|
|
15
|
-
*
|
|
15
|
+
*
|
|
16
|
+
* On macOS the filter has two layers:
|
|
17
|
+
* 1. GPU-required services without a `cpuFallback` image (e.g. legacy
|
|
18
|
+
* llm-proxy) are always excluded — Docker on Mac can't reach the GPU,
|
|
19
|
+
* so the container would be useless.
|
|
20
|
+
* 2. Any service the user explicitly opted into native mode (via the
|
|
21
|
+
* wizard's native-services step → WizardState.nativeServices) is also
|
|
22
|
+
* excluded; it'll be installed as a LaunchAgent instead.
|
|
16
23
|
*/
|
|
17
24
|
export function getComposeServices(state, registry) {
|
|
18
25
|
const all = getAllEnabledServices(state, registry);
|
|
26
|
+
const nativeIds = new Set(state.nativeServices ?? []);
|
|
19
27
|
if (state.platform === 'darwin') {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
28
|
+
return all.filter((s) => {
|
|
29
|
+
if (nativeIds.has(s.id))
|
|
30
|
+
return false;
|
|
31
|
+
if (s.gpu && !s.cpuFallback)
|
|
32
|
+
return false;
|
|
33
|
+
return true;
|
|
34
|
+
});
|
|
23
35
|
}
|
|
24
36
|
return all;
|
|
25
37
|
}
|
|
@@ -28,6 +40,7 @@ export function getComposeServices(state, registry) {
|
|
|
28
40
|
* Other GPU types (amd Vulkan, none) fall back to the plain CPU image.
|
|
29
41
|
*/
|
|
30
42
|
const CPU_FALLBACK_GPU_VARIANTS = new Set(['nvidia', 'amd-rocm']);
|
|
43
|
+
const FIRST_PARTY_PREFIX = 'ghcr.io/alexberardi/';
|
|
31
44
|
/** Whether a service should use a GPU image variant + GPU runtime config for the host. */
|
|
32
45
|
function shouldUseGpuVariant(service, gpuType) {
|
|
33
46
|
if (!service.gpu || !gpuType)
|
|
@@ -179,7 +192,14 @@ function generateInfraBlock(infra, state) {
|
|
|
179
192
|
return lines;
|
|
180
193
|
}
|
|
181
194
|
function getServiceImage(service, state) {
|
|
182
|
-
|
|
195
|
+
const raw = service.ghcrImage ?? service.image;
|
|
196
|
+
const isFirstParty = raw.startsWith(FIRST_PARTY_PREFIX);
|
|
197
|
+
const baseImage = raw.includes(':') ? raw.slice(0, raw.lastIndexOf(':')) : raw;
|
|
198
|
+
// Third-party images (e.g. go2rtc) keep their original tag
|
|
199
|
+
if (!isFirstParty)
|
|
200
|
+
return raw;
|
|
201
|
+
// Build tag with optional GPU suffix
|
|
202
|
+
let gpuSuffix = '';
|
|
183
203
|
if (shouldUseGpuVariant(service, state.hardware?.gpuType)) {
|
|
184
204
|
const variantSuffix = {
|
|
185
205
|
nvidia: '-cuda',
|
|
@@ -187,12 +207,9 @@ function getServiceImage(service, state) {
|
|
|
187
207
|
'amd-rocm': '-rocm',
|
|
188
208
|
none: '-cpu',
|
|
189
209
|
};
|
|
190
|
-
|
|
191
|
-
if (suffix) {
|
|
192
|
-
image = image.includes(':') ? image + suffix : image + ':latest' + suffix;
|
|
193
|
-
}
|
|
210
|
+
gpuSuffix = variantSuffix[state.hardware.gpuType] ?? '';
|
|
194
211
|
}
|
|
195
|
-
return
|
|
212
|
+
return `${baseImage}:\${JARVIS_IMAGE_TAG:-latest}${gpuSuffix}`;
|
|
196
213
|
}
|
|
197
214
|
function pushGpuConfig(lines, service, state) {
|
|
198
215
|
if (!service.gpu)
|
|
@@ -308,6 +325,12 @@ function generateServiceBlock(service, state, registry) {
|
|
|
308
325
|
if (service.id === 'jarvis-command-center' && state.relayEnabled) {
|
|
309
326
|
lines.push(' JARVIS_RELAY_URL: ${JARVIS_RELAY_URL:-}');
|
|
310
327
|
}
|
|
328
|
+
// Admin → host platform: env-generator writes HOST_OS to .env at install
|
|
329
|
+
// time; admin reads it via getHostPlatform() to know whether to expose the
|
|
330
|
+
// native-services UI (Docker masks the real platform from process.platform).
|
|
331
|
+
if (service.id === 'jarvis-admin') {
|
|
332
|
+
lines.push(' HOST_OS: ${HOST_OS:-linux}');
|
|
333
|
+
}
|
|
311
334
|
// go2rtc: standalone streaming gateway, no Jarvis auth/config needed
|
|
312
335
|
if (service.id === 'go2rtc') {
|
|
313
336
|
// No app-to-app auth, no extra environment — skip to volumes/network
|