@gachlab/devup 0.9.3 → 0.10.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/dist/control-plane/socket-server.d.ts +23 -0
- package/dist/control-plane/socket-server.d.ts.map +1 -1
- package/dist/index.js +96 -8
- package/dist/index.js.map +1 -1
- package/dist/orchestrator/daemon.d.ts.map +1 -1
- package/dist/tui/App.d.ts.map +1 -1
- package/dist/tui/hooks/useControlPlane.d.ts +6 -1
- package/dist/tui/hooks/useControlPlane.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -9,6 +9,25 @@ import type { ProcessState } from '../process/types.js';
|
|
|
9
9
|
* to the socket file already has the same uid as the devup process — no
|
|
10
10
|
* additional auth needed. Strictly local; TCP exposure is intentionally
|
|
11
11
|
* out of scope. */
|
|
12
|
+
export interface ServiceStatEntry {
|
|
13
|
+
cpu: number;
|
|
14
|
+
memMB: number;
|
|
15
|
+
}
|
|
16
|
+
export interface StatsResult {
|
|
17
|
+
services: Record<string, ServiceStatEntry>;
|
|
18
|
+
system: {
|
|
19
|
+
totalMemMB: number;
|
|
20
|
+
freeMemMB: number;
|
|
21
|
+
cpuCores: number;
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
export interface ProxyInfo {
|
|
25
|
+
active: boolean;
|
|
26
|
+
provider: string;
|
|
27
|
+
domain: string;
|
|
28
|
+
tls: boolean;
|
|
29
|
+
routes: Record<string, string>;
|
|
30
|
+
}
|
|
12
31
|
export interface RpcContext {
|
|
13
32
|
/** State of every service (read-only snapshot). */
|
|
14
33
|
states(): Map<string, ProcessState>;
|
|
@@ -23,6 +42,10 @@ export interface RpcContext {
|
|
|
23
42
|
watchLogs(svcName: string | null, onLine: (svc: string, line: string) => void): () => void;
|
|
24
43
|
/** Subscribe to service-state changes. Returns an unsubscribe function. */
|
|
25
44
|
watchStatus(onUpdate: (name: string, state: ProcessState) => void): () => void;
|
|
45
|
+
/** Per-service CPU/mem stats + system totals. */
|
|
46
|
+
getStats(): Promise<StatsResult>;
|
|
47
|
+
/** Active proxy configuration, or null when no proxy is running. */
|
|
48
|
+
getProxyInfo(): ProxyInfo | null;
|
|
26
49
|
}
|
|
27
50
|
export interface SocketServerHandle {
|
|
28
51
|
server: Server;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"socket-server.d.ts","sourceRoot":"","sources":["../../src/control-plane/socket-server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,MAAM,EAAe,MAAM,UAAU,CAAC;AAMlE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAExD;;;;;;;;oBAQoB;AAEpB,MAAM,WAAW,UAAU;IACzB,mDAAmD;IACnD,MAAM,IAAI,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IACpC,iCAAiC;IACjC,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACrC,8BAA8B;IAC9B,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,yFAAyF;IACzF,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAC5D;2CACuC;IACvC,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,EAAE,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;IAC3F,2EAA2E;IAC3E,WAAW,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"socket-server.d.ts","sourceRoot":"","sources":["../../src/control-plane/socket-server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,MAAM,EAAe,MAAM,UAAU,CAAC;AAMlE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAExD;;;;;;;;oBAQoB;AAEpB,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;IAC3C,MAAM,EAAE;QACN,UAAU,EAAE,MAAM,CAAC;QACnB,SAAS,EAAE,MAAM,CAAC;QAClB,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC;CACH;AAED,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,OAAO,CAAC;IACb,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAChC;AAED,MAAM,WAAW,UAAU;IACzB,mDAAmD;IACnD,MAAM,IAAI,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IACpC,iCAAiC;IACjC,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACrC,8BAA8B;IAC9B,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,yFAAyF;IACzF,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAC5D;2CACuC;IACvC,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,EAAE,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;IAC3F,2EAA2E;IAC3E,WAAW,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;IAC/E,iDAAiD;IACjD,QAAQ,IAAI,OAAO,CAAC,WAAW,CAAC,CAAC;IACjC,oEAAoE;IACpE,YAAY,IAAI,SAAS,GAAG,IAAI,CAAC;CAClC;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAG7D;AAED,wBAAsB,iBAAiB,CACrC,WAAW,EAAE,MAAM,EACnB,GAAG,EAAE,UAAU,EACf,IAAI,GAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;CAAO,GAC1D,OAAO,CAAC,kBAAkB,CAAC,CA+C7B"}
|
package/dist/index.js
CHANGED
|
@@ -847,8 +847,10 @@ async function dispatch(method, params, ctx) {
|
|
|
847
847
|
for (const [name, st] of ctx.states()) {
|
|
848
848
|
out.push(serializeState(name, st));
|
|
849
849
|
}
|
|
850
|
-
return { services: out };
|
|
850
|
+
return { services: out, proxy: ctx.getProxyInfo() };
|
|
851
851
|
}
|
|
852
|
+
case "stats":
|
|
853
|
+
return await ctx.getStats();
|
|
852
854
|
case "restart": {
|
|
853
855
|
const svc = stringOrThrow(params["svc"] ?? params["service"], "svc");
|
|
854
856
|
await ctx.restart(svc);
|
|
@@ -951,7 +953,7 @@ function openStream(socketPath, method, params, onFrame, onError) {
|
|
|
951
953
|
import { spawn as spawn4 } from "child_process";
|
|
952
954
|
import { writeFileSync as writeFileSync2, readFileSync as readFileSync3, existsSync as existsSync10, unlinkSync as unlinkSync2, mkdirSync as mkdirSync3, createReadStream } from "fs";
|
|
953
955
|
import { join as join8 } from "path";
|
|
954
|
-
import { homedir as homedir3 } from "os";
|
|
956
|
+
import { homedir as homedir3, totalmem, freemem, cpus } from "os";
|
|
955
957
|
import { setTimeout as sleep } from "timers/promises";
|
|
956
958
|
import { createInterface as createInterface3 } from "readline";
|
|
957
959
|
|
|
@@ -1874,6 +1876,7 @@ async function daemonBody(opts) {
|
|
|
1874
1876
|
const logBus = new Broadcaster();
|
|
1875
1877
|
const stateBus = new Broadcaster();
|
|
1876
1878
|
const lazyProxies = /* @__PURE__ */ new Map();
|
|
1879
|
+
const prevCpuMap = /* @__PURE__ */ new Map();
|
|
1877
1880
|
let externals = [];
|
|
1878
1881
|
let socket = null;
|
|
1879
1882
|
let healthTimer = null;
|
|
@@ -1983,7 +1986,48 @@ async function daemonBody(opts) {
|
|
|
1983
1986
|
watchLogs: (svcName, onLine) => logBus.subscribe(({ svc, text }) => {
|
|
1984
1987
|
if (svcName === null || svc === svcName) onLine(svc, text);
|
|
1985
1988
|
}),
|
|
1986
|
-
watchStatus: (onUpdate) => stateBus.subscribe(({ name, state }) => onUpdate(name, state))
|
|
1989
|
+
watchStatus: (onUpdate) => stateBus.subscribe(({ name, state }) => onUpdate(name, state)),
|
|
1990
|
+
async getStats() {
|
|
1991
|
+
const pids = [];
|
|
1992
|
+
const pidToName = /* @__PURE__ */ new Map();
|
|
1993
|
+
for (const [name, st] of mgr.state) {
|
|
1994
|
+
if (st.pid) {
|
|
1995
|
+
pids.push(st.pid);
|
|
1996
|
+
pidToName.set(st.pid, name);
|
|
1997
|
+
}
|
|
1998
|
+
}
|
|
1999
|
+
const raw = pids.length ? await platform.getProcessStats(pids) : /* @__PURE__ */ new Map();
|
|
2000
|
+
const services2 = {};
|
|
2001
|
+
for (const [name] of mgr.state) {
|
|
2002
|
+
services2[name] = { cpu: 0, memMB: 0 };
|
|
2003
|
+
}
|
|
2004
|
+
for (const [pid, data] of raw) {
|
|
2005
|
+
const name = pidToName.get(pid);
|
|
2006
|
+
if (!name) continue;
|
|
2007
|
+
const prev = prevCpuMap.get(name) ?? { time: Date.now(), cpu: 0 };
|
|
2008
|
+
const cpu = calcCpuPercent(data.cpuSeconds, prev.cpu, prev.time);
|
|
2009
|
+
prevCpuMap.set(name, { time: Date.now(), cpu: data.cpuSeconds });
|
|
2010
|
+
services2[name] = { cpu: Math.round(cpu * 10) / 10, memMB: Math.round(data.rss / 1024 * 10) / 10 };
|
|
2011
|
+
}
|
|
2012
|
+
return {
|
|
2013
|
+
services: services2,
|
|
2014
|
+
system: {
|
|
2015
|
+
totalMemMB: Math.round(totalmem() / 1024 / 1024),
|
|
2016
|
+
freeMemMB: Math.round(freemem() / 1024 / 1024),
|
|
2017
|
+
cpuCores: cpus().length
|
|
2018
|
+
}
|
|
2019
|
+
};
|
|
2020
|
+
},
|
|
2021
|
+
getProxyInfo() {
|
|
2022
|
+
if (!proxyProvider || !proxyOpts || !cliArgs.proxy) return null;
|
|
2023
|
+
return {
|
|
2024
|
+
active: true,
|
|
2025
|
+
provider: proxyProvider.name,
|
|
2026
|
+
domain: proxyOpts.domain,
|
|
2027
|
+
tls: proxyOpts.tls,
|
|
2028
|
+
routes: proxyOpts.routes
|
|
2029
|
+
};
|
|
2030
|
+
}
|
|
1987
2031
|
}, { onLog: (msg) => writeDevupLog(msg) });
|
|
1988
2032
|
healthTimer = setInterval(() => {
|
|
1989
2033
|
void mgr.checkAllHealth();
|
|
@@ -3102,8 +3146,10 @@ function useLogsPause(setPaused, logsPaused, logsScrollOffset) {
|
|
|
3102
3146
|
import { useEffect as useEffect5, useRef as useRef3 } from "react";
|
|
3103
3147
|
import { createInterface as createInterface5 } from "readline";
|
|
3104
3148
|
import { createReadStream as createReadStream3, existsSync as existsSync15 } from "fs";
|
|
3105
|
-
|
|
3149
|
+
import { totalmem as totalmem2, freemem as freemem2, cpus as cpus2 } from "os";
|
|
3150
|
+
function useControlPlane(manager, projectName, logSink, pushLog, logBus, stateBus, platform, proxy) {
|
|
3106
3151
|
const handleRef = useRef3(null);
|
|
3152
|
+
const prevCpuMap = useRef3(/* @__PURE__ */ new Map());
|
|
3107
3153
|
useEffect5(() => {
|
|
3108
3154
|
if (!manager) return;
|
|
3109
3155
|
let handle = null;
|
|
@@ -3135,6 +3181,47 @@ function useControlPlane(manager, projectName, logSink, pushLog, logBus, stateBu
|
|
|
3135
3181
|
},
|
|
3136
3182
|
watchStatus: (onUpdate) => {
|
|
3137
3183
|
return stateBus.subscribe(({ name, state }) => onUpdate(name, state));
|
|
3184
|
+
},
|
|
3185
|
+
async getStats() {
|
|
3186
|
+
const pids = [];
|
|
3187
|
+
const pidToName = /* @__PURE__ */ new Map();
|
|
3188
|
+
for (const [name, st] of manager.state) {
|
|
3189
|
+
if (st.pid) {
|
|
3190
|
+
pids.push(st.pid);
|
|
3191
|
+
pidToName.set(st.pid, name);
|
|
3192
|
+
}
|
|
3193
|
+
}
|
|
3194
|
+
const raw = pids.length ? await platform.getProcessStats(pids) : /* @__PURE__ */ new Map();
|
|
3195
|
+
const services = {};
|
|
3196
|
+
for (const [name] of manager.state) {
|
|
3197
|
+
services[name] = { cpu: 0, memMB: 0 };
|
|
3198
|
+
}
|
|
3199
|
+
for (const [pid, data] of raw) {
|
|
3200
|
+
const name = pidToName.get(pid);
|
|
3201
|
+
if (!name) continue;
|
|
3202
|
+
const prev = prevCpuMap.current.get(name) ?? { time: Date.now(), cpu: 0 };
|
|
3203
|
+
const cpu = calcCpuPercent(data.cpuSeconds, prev.cpu, prev.time);
|
|
3204
|
+
prevCpuMap.current.set(name, { time: Date.now(), cpu: data.cpuSeconds });
|
|
3205
|
+
services[name] = { cpu: Math.round(cpu * 10) / 10, memMB: Math.round(data.rss / 1024 * 10) / 10 };
|
|
3206
|
+
}
|
|
3207
|
+
return {
|
|
3208
|
+
services,
|
|
3209
|
+
system: {
|
|
3210
|
+
totalMemMB: Math.round(totalmem2() / 1024 / 1024),
|
|
3211
|
+
freeMemMB: Math.round(freemem2() / 1024 / 1024),
|
|
3212
|
+
cpuCores: cpus2().length
|
|
3213
|
+
}
|
|
3214
|
+
};
|
|
3215
|
+
},
|
|
3216
|
+
getProxyInfo() {
|
|
3217
|
+
if (!proxy) return null;
|
|
3218
|
+
return {
|
|
3219
|
+
active: true,
|
|
3220
|
+
provider: proxy.provider.name,
|
|
3221
|
+
domain: proxy.opts.domain,
|
|
3222
|
+
tls: proxy.opts.tls,
|
|
3223
|
+
routes: proxy.opts.routes
|
|
3224
|
+
};
|
|
3138
3225
|
}
|
|
3139
3226
|
}, { onLog: (msg) => pushLog("devup", msg, 12) });
|
|
3140
3227
|
handleRef.current = handle;
|
|
@@ -3146,7 +3233,7 @@ function useControlPlane(manager, projectName, logSink, pushLog, logBus, stateBu
|
|
|
3146
3233
|
void handle?.close();
|
|
3147
3234
|
handleRef.current = null;
|
|
3148
3235
|
};
|
|
3149
|
-
}, [manager, projectName, logSink, pushLog, logBus, stateBus]);
|
|
3236
|
+
}, [manager, projectName, logSink, pushLog, logBus, stateBus, platform, proxy]);
|
|
3150
3237
|
return handleRef;
|
|
3151
3238
|
}
|
|
3152
3239
|
|
|
@@ -3289,7 +3376,7 @@ function StatsPanel({ states, stats, sortMode, maxNameLen, height, focused, scro
|
|
|
3289
3376
|
const statsObj = Object.fromEntries([...stats].map(([k, v]) => [k, v]));
|
|
3290
3377
|
const apis = sortServiceNames(names.filter((n) => states.get(n).svc.type === "api"), sortMode, statsObj, stObj);
|
|
3291
3378
|
const webs = sortServiceNames(names.filter((n) => states.get(n).svc.type === "web"), sortMode, statsObj, stObj);
|
|
3292
|
-
const
|
|
3379
|
+
const cpus3 = os.cpus().length;
|
|
3293
3380
|
const totalGB = (os.totalmem() / 1024 / 1024 / 1024).toFixed(1);
|
|
3294
3381
|
const usedGB = (parseFloat(totalGB) - os.freemem() / 1024 / 1024 / 1024).toFixed(1);
|
|
3295
3382
|
const load = os.loadavg()[0].toFixed(2);
|
|
@@ -3342,7 +3429,7 @@ function StatsPanel({ states, stats, sortMode, maxNameLen, height, focused, scro
|
|
|
3342
3429
|
] }),
|
|
3343
3430
|
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
3344
3431
|
" System: ",
|
|
3345
|
-
|
|
3432
|
+
cpus3,
|
|
3346
3433
|
"c Load ",
|
|
3347
3434
|
load,
|
|
3348
3435
|
" RAM ",
|
|
@@ -3754,7 +3841,8 @@ function App({ config, services, cliArgs, platform, env, baseCwd, proxyProvider,
|
|
|
3754
3841
|
onToggleProxy: () => {
|
|
3755
3842
|
}
|
|
3756
3843
|
});
|
|
3757
|
-
const
|
|
3844
|
+
const proxyCtx = proxyProvider && proxyOpts ? { provider: proxyProvider, opts: proxyOpts } : null;
|
|
3845
|
+
const socketServer = useControlPlane(pm.manager, config.name, logSink, pm.pushLog, pm.logBus, pm.stateBus, platform, proxyCtx);
|
|
3758
3846
|
const shutdown = useCallback3(async () => {
|
|
3759
3847
|
lazyProxies.current.forEach((p) => p.destroy());
|
|
3760
3848
|
await socketServer.current?.close();
|