@gachlab/devup 0.1.0 → 0.1.1
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/index.js +132 -16
- package/dist/index.js.map +1 -1
- package/dist/process/installer.d.ts.map +1 -1
- package/dist/tui/App.d.ts.map +1 -1
- package/dist/tui/LogsPanel.d.ts +3 -1
- package/dist/tui/LogsPanel.d.ts.map +1 -1
- package/dist/tui/StatsPanel.d.ts +3 -1
- package/dist/tui/StatsPanel.d.ts.map +1 -1
- package/dist/tui/hooks/useKeyBindings.d.ts +6 -0
- package/dist/tui/hooks/useKeyBindings.d.ts.map +1 -1
- package/package.json +16 -7
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
|
-
import
|
|
4
|
+
import React6 from "react";
|
|
5
5
|
import { render } from "ink";
|
|
6
6
|
import { join as join4 } from "path";
|
|
7
7
|
import { homedir } from "os";
|
|
@@ -384,7 +384,7 @@ var tagColors = [
|
|
|
384
384
|
];
|
|
385
385
|
|
|
386
386
|
// src/tui/App.tsx
|
|
387
|
-
import { useEffect as
|
|
387
|
+
import { useEffect as useEffect5, useState as useState5, useCallback as useCallback3, useRef as useRef3 } from "react";
|
|
388
388
|
import { Box as Box6, Text as Text6, useStdout } from "ink";
|
|
389
389
|
|
|
390
390
|
// src/tui/hooks/useProcessManager.ts
|
|
@@ -449,7 +449,8 @@ function installService(cwd, env, onLog) {
|
|
|
449
449
|
}
|
|
450
450
|
onLog?.("\u{1F4E6} npm install...");
|
|
451
451
|
return new Promise((resolve3) => {
|
|
452
|
-
const
|
|
452
|
+
const command = process.platform === "win32" ? "npm.cmd" : "npm";
|
|
453
|
+
const proc = spawn(command, ["install"], { cwd, env, stdio: ["ignore", "ignore", "pipe"] });
|
|
453
454
|
let stderr = "";
|
|
454
455
|
proc.stderr?.on("data", (d) => {
|
|
455
456
|
stderr += d.toString();
|
|
@@ -464,6 +465,10 @@ function installService(cwd, env, onLog) {
|
|
|
464
465
|
resolve3(true);
|
|
465
466
|
}
|
|
466
467
|
});
|
|
468
|
+
proc.on("error", (err) => {
|
|
469
|
+
onLog?.(`\u26A0 spawn error: ${err.message}`);
|
|
470
|
+
resolve3(false);
|
|
471
|
+
});
|
|
467
472
|
});
|
|
468
473
|
}
|
|
469
474
|
|
|
@@ -680,7 +685,9 @@ function useKeyBindings(opts) {
|
|
|
680
685
|
logsPaused: false,
|
|
681
686
|
showTimestamps: false,
|
|
682
687
|
sortIdx: 0,
|
|
683
|
-
proxyEnabled: false
|
|
688
|
+
proxyEnabled: false,
|
|
689
|
+
logsScrollOffset: 0,
|
|
690
|
+
statsScrollOffset: 0
|
|
684
691
|
});
|
|
685
692
|
const setModal = useCallback2((modal) => setState((s) => ({ ...s, modal })), []);
|
|
686
693
|
const setFilter = useCallback2((f) => setState((s) => ({ ...s, logFilter: f, modal: "none" })), []);
|
|
@@ -702,9 +709,72 @@ function useKeyBindings(opts) {
|
|
|
702
709
|
else if (input === "T") {
|
|
703
710
|
opts.onToggleProxy();
|
|
704
711
|
setState((s) => ({ ...s, proxyEnabled: !s.proxyEnabled }));
|
|
712
|
+
} else if (key.upArrow) {
|
|
713
|
+
setState((s) => {
|
|
714
|
+
if (s.panel === "logs") {
|
|
715
|
+
return { ...s, logsScrollOffset: Math.max(0, s.logsScrollOffset - 1) };
|
|
716
|
+
} else if (s.panel === "stats") {
|
|
717
|
+
return { ...s, statsScrollOffset: Math.max(0, s.statsScrollOffset - 1) };
|
|
718
|
+
}
|
|
719
|
+
return s;
|
|
720
|
+
});
|
|
721
|
+
} else if (key.downArrow) {
|
|
722
|
+
setState((s) => {
|
|
723
|
+
if (s.panel === "logs") {
|
|
724
|
+
return { ...s, logsScrollOffset: s.logsScrollOffset + 1 };
|
|
725
|
+
} else if (s.panel === "stats") {
|
|
726
|
+
return { ...s, statsScrollOffset: s.statsScrollOffset + 1 };
|
|
727
|
+
}
|
|
728
|
+
return s;
|
|
729
|
+
});
|
|
730
|
+
} else if (input === "[" || key.ctrl && input === "b") {
|
|
731
|
+
setState((s) => {
|
|
732
|
+
if (s.panel === "logs") {
|
|
733
|
+
return { ...s, logsScrollOffset: Math.max(0, s.logsScrollOffset - 10) };
|
|
734
|
+
} else if (s.panel === "stats") {
|
|
735
|
+
return { ...s, statsScrollOffset: Math.max(0, s.statsScrollOffset - 10) };
|
|
736
|
+
}
|
|
737
|
+
return s;
|
|
738
|
+
});
|
|
739
|
+
} else if (input === "]" || key.ctrl && input === "f") {
|
|
740
|
+
setState((s) => {
|
|
741
|
+
if (s.panel === "logs") {
|
|
742
|
+
return { ...s, logsScrollOffset: s.logsScrollOffset + 10 };
|
|
743
|
+
} else if (s.panel === "stats") {
|
|
744
|
+
return { ...s, statsScrollOffset: s.statsScrollOffset + 10 };
|
|
745
|
+
}
|
|
746
|
+
return s;
|
|
747
|
+
});
|
|
748
|
+
} else if (key.ctrl && input === "a") {
|
|
749
|
+
setState((s) => {
|
|
750
|
+
if (s.panel === "logs") {
|
|
751
|
+
return { ...s, logsScrollOffset: 0 };
|
|
752
|
+
} else if (s.panel === "stats") {
|
|
753
|
+
return { ...s, statsScrollOffset: 0 };
|
|
754
|
+
}
|
|
755
|
+
return s;
|
|
756
|
+
});
|
|
757
|
+
} else if (key.ctrl && input === "e") {
|
|
758
|
+
setState((s) => {
|
|
759
|
+
if (s.panel === "logs") {
|
|
760
|
+
return { ...s, logsScrollOffset: Number.MAX_SAFE_INTEGER };
|
|
761
|
+
} else if (s.panel === "stats") {
|
|
762
|
+
return { ...s, statsScrollOffset: Number.MAX_SAFE_INTEGER };
|
|
763
|
+
}
|
|
764
|
+
return s;
|
|
765
|
+
});
|
|
705
766
|
}
|
|
706
767
|
}, { isActive });
|
|
707
|
-
return {
|
|
768
|
+
return {
|
|
769
|
+
...state,
|
|
770
|
+
setModal,
|
|
771
|
+
setFilter,
|
|
772
|
+
setSearch,
|
|
773
|
+
sortMode: SORT_MODES[state.sortIdx],
|
|
774
|
+
// Funciones para resetear el scroll cuando cambia el contenido
|
|
775
|
+
resetLogsScroll: useCallback2(() => setState((s) => ({ ...s, logsScrollOffset: 0 })), []),
|
|
776
|
+
resetStatsScroll: useCallback2(() => setState((s) => ({ ...s, statsScrollOffset: 0 })), [])
|
|
777
|
+
};
|
|
708
778
|
}
|
|
709
779
|
|
|
710
780
|
// src/tui/hooks/useProxySync.ts
|
|
@@ -733,18 +803,32 @@ function useProxySync(provider, opts, states, enabled) {
|
|
|
733
803
|
}
|
|
734
804
|
|
|
735
805
|
// src/tui/LogsPanel.tsx
|
|
806
|
+
import { useEffect as useEffect3 } from "react";
|
|
736
807
|
import { Box, Text } from "ink";
|
|
737
808
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
738
|
-
function LogsPanel({ logs, filter, searchTerm, paused, showTimestamps, maxNameLen, height, focused }) {
|
|
809
|
+
function LogsPanel({ logs, filter, searchTerm, paused, showTimestamps, maxNameLen, height, focused, scrollOffset, resetScroll }) {
|
|
739
810
|
const filtered = filter ? logs.filter((l) => l.svcName === filter) : logs;
|
|
740
811
|
const contentHeight = height - 2;
|
|
741
|
-
const
|
|
812
|
+
const totalLines = filtered.length;
|
|
813
|
+
let startIndex = 0;
|
|
814
|
+
if (scrollOffset === Number.MAX_SAFE_INTEGER) {
|
|
815
|
+
startIndex = Math.max(0, totalLines - contentHeight);
|
|
816
|
+
} else if (scrollOffset > 0) {
|
|
817
|
+
startIndex = Math.min(scrollOffset, Math.max(0, totalLines - contentHeight));
|
|
818
|
+
} else {
|
|
819
|
+
startIndex = Math.max(0, totalLines - contentHeight);
|
|
820
|
+
}
|
|
821
|
+
const visible = filtered.slice(startIndex, startIndex + contentHeight);
|
|
822
|
+
useEffect3(() => {
|
|
823
|
+
resetScroll();
|
|
824
|
+
}, [filter, searchTerm, resetScroll]);
|
|
742
825
|
const label = [
|
|
743
826
|
"Logs",
|
|
744
827
|
filter ? `[${filter}]` : "",
|
|
745
828
|
searchTerm ? `/${searchTerm}` : "",
|
|
746
829
|
paused ? "[PAUSED]" : "",
|
|
747
|
-
`${filtered.length} lines
|
|
830
|
+
`${filtered.length} lines`,
|
|
831
|
+
focused ? `(${startIndex + 1}-${Math.min(startIndex + contentHeight, totalLines)}/${totalLines})` : ""
|
|
748
832
|
].filter(Boolean).join(" ");
|
|
749
833
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: focused ? "cyan" : "gray", height, children: [
|
|
750
834
|
/* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(Text, { bold: true, color: "cyan", children: [
|
|
@@ -772,6 +856,7 @@ function LogsPanel({ logs, filter, searchTerm, paused, showTimestamps, maxNameLe
|
|
|
772
856
|
}
|
|
773
857
|
|
|
774
858
|
// src/tui/StatsPanel.tsx
|
|
859
|
+
import { useEffect as useEffect4 } from "react";
|
|
775
860
|
import { Box as Box2, Text as Text2 } from "ink";
|
|
776
861
|
import os from "os";
|
|
777
862
|
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
@@ -822,7 +907,7 @@ function ColHeader({ ml }) {
|
|
|
822
907
|
"Up".padStart(6)
|
|
823
908
|
] });
|
|
824
909
|
}
|
|
825
|
-
function StatsPanel({ states, stats, sortMode, maxNameLen, height, focused }) {
|
|
910
|
+
function StatsPanel({ states, stats, sortMode, maxNameLen, height, focused, scrollOffset, resetScroll }) {
|
|
826
911
|
const names = [...states.keys()];
|
|
827
912
|
const stObj = Object.fromEntries([...states].map(([k, v]) => [k, { errors: v.errors }]));
|
|
828
913
|
const statsObj = Object.fromEntries([...stats].map(([k, v]) => [k, v]));
|
|
@@ -847,9 +932,30 @@ function StatsPanel({ states, stats, sortMode, maxNameLen, height, focused }) {
|
|
|
847
932
|
const stackMem = totalMemMB >= 1024 ? (totalMemMB / 1024).toFixed(2) + " GB" : totalMemMB.toFixed(1) + " MB";
|
|
848
933
|
const ml = maxNameLen;
|
|
849
934
|
const contentHeight = height - 2;
|
|
935
|
+
const maxApiRows = Math.max(0, apis.length - (contentHeight - 2));
|
|
936
|
+
const maxWebRows = Math.max(0, webs.length - (contentHeight - 2));
|
|
937
|
+
let apiStartIndex = 0;
|
|
938
|
+
let webStartIndex = 0;
|
|
939
|
+
if (scrollOffset === Number.MAX_SAFE_INTEGER) {
|
|
940
|
+
apiStartIndex = maxApiRows;
|
|
941
|
+
webStartIndex = maxWebRows;
|
|
942
|
+
} else if (scrollOffset > 0) {
|
|
943
|
+
apiStartIndex = Math.min(scrollOffset, maxApiRows);
|
|
944
|
+
webStartIndex = Math.min(scrollOffset, maxWebRows);
|
|
945
|
+
}
|
|
946
|
+
const visibleApis = apis.slice(apiStartIndex, apiStartIndex + contentHeight - 2);
|
|
947
|
+
const visibleWebs = webs.slice(webStartIndex, webStartIndex + contentHeight - 2);
|
|
948
|
+
useEffect4(() => {
|
|
949
|
+
resetScroll();
|
|
950
|
+
}, [sortMode, resetScroll]);
|
|
951
|
+
const totalServices = apis.length + webs.length;
|
|
952
|
+
const positionInfo = focused ? `(${Math.max(apiStartIndex, webStartIndex) + 1}-${Math.max(apiStartIndex, webStartIndex) + contentHeight - 2}/${totalServices})` : "";
|
|
850
953
|
return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", borderStyle: "round", borderColor: focused ? "green" : "gray", height, children: [
|
|
851
954
|
/* @__PURE__ */ jsxs2(Box2, { children: [
|
|
852
|
-
/* @__PURE__ */
|
|
955
|
+
/* @__PURE__ */ jsxs2(Text2, { bold: true, color: "green", children: [
|
|
956
|
+
" Stats ",
|
|
957
|
+
positionInfo
|
|
958
|
+
] }),
|
|
853
959
|
/* @__PURE__ */ jsxs2(Text2, { dimColor: true, children: [
|
|
854
960
|
"System: ",
|
|
855
961
|
cpus,
|
|
@@ -887,7 +993,7 @@ function StatsPanel({ states, stats, sortMode, maxNameLen, height, focused }) {
|
|
|
887
993
|
")"
|
|
888
994
|
] }),
|
|
889
995
|
/* @__PURE__ */ jsx2(ColHeader, { ml }),
|
|
890
|
-
|
|
996
|
+
visibleApis.map((n) => /* @__PURE__ */ jsx2(Row, { name: n, st: states.get(n), stat: stats.get(n), ml }, n))
|
|
891
997
|
] }),
|
|
892
998
|
/* @__PURE__ */ jsx2(Box2, { flexDirection: "column", width: 1, children: Array.from({ length: contentHeight }, (_, i) => /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: "\u2502" }, i)) }),
|
|
893
999
|
/* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", flexGrow: 1, flexBasis: 0, children: [
|
|
@@ -897,7 +1003,7 @@ function StatsPanel({ states, stats, sortMode, maxNameLen, height, focused }) {
|
|
|
897
1003
|
")"
|
|
898
1004
|
] }),
|
|
899
1005
|
/* @__PURE__ */ jsx2(ColHeader, { ml }),
|
|
900
|
-
|
|
1006
|
+
visibleWebs.map((n) => /* @__PURE__ */ jsx2(Row, { name: n, st: states.get(n), stat: stats.get(n), ml }, n))
|
|
901
1007
|
] })
|
|
902
1008
|
] })
|
|
903
1009
|
] });
|
|
@@ -912,6 +1018,12 @@ function StatusBar() {
|
|
|
912
1018
|
" Quit ",
|
|
913
1019
|
/* @__PURE__ */ jsx3(Text3, { bold: true, children: "Tab" }),
|
|
914
1020
|
" Switch ",
|
|
1021
|
+
/* @__PURE__ */ jsx3(Text3, { bold: true, children: "\u2191\u2193" }),
|
|
1022
|
+
" Scroll ",
|
|
1023
|
+
/* @__PURE__ */ jsx3(Text3, { bold: true, children: "PgUp/PgDn" }),
|
|
1024
|
+
" Page ",
|
|
1025
|
+
/* @__PURE__ */ jsx3(Text3, { bold: true, children: "Ctrl+A/E" }),
|
|
1026
|
+
" Home/End ",
|
|
915
1027
|
/* @__PURE__ */ jsx3(Text3, { bold: true, children: "c" }),
|
|
916
1028
|
" Clear ",
|
|
917
1029
|
/* @__PURE__ */ jsx3(Text3, { bold: true, children: "f" }),
|
|
@@ -1114,7 +1226,7 @@ function App({ config, services, cliArgs, platform, env, baseCwd, proxyProvider,
|
|
|
1114
1226
|
}
|
|
1115
1227
|
});
|
|
1116
1228
|
useProxySync(proxyProvider, proxyOpts, pm.states, kb.proxyEnabled);
|
|
1117
|
-
|
|
1229
|
+
useEffect5(() => {
|
|
1118
1230
|
if (booted || !pm.manager) return;
|
|
1119
1231
|
setBooted(true);
|
|
1120
1232
|
const mgr = pm.manager;
|
|
@@ -1239,7 +1351,9 @@ function App({ config, services, cliArgs, platform, env, baseCwd, proxyProvider,
|
|
|
1239
1351
|
showTimestamps: kb.showTimestamps,
|
|
1240
1352
|
maxNameLen,
|
|
1241
1353
|
height: logsHeight,
|
|
1242
|
-
focused: kb.panel === "logs"
|
|
1354
|
+
focused: kb.panel === "logs",
|
|
1355
|
+
scrollOffset: kb.logsScrollOffset,
|
|
1356
|
+
resetScroll: kb.resetLogsScroll
|
|
1243
1357
|
}
|
|
1244
1358
|
),
|
|
1245
1359
|
/* @__PURE__ */ jsx6(
|
|
@@ -1250,7 +1364,9 @@ function App({ config, services, cliArgs, platform, env, baseCwd, proxyProvider,
|
|
|
1250
1364
|
sortMode: kb.sortMode,
|
|
1251
1365
|
maxNameLen,
|
|
1252
1366
|
height: statsHeight,
|
|
1253
|
-
focused: kb.panel === "stats"
|
|
1367
|
+
focused: kb.panel === "stats",
|
|
1368
|
+
scrollOffset: kb.statsScrollOffset,
|
|
1369
|
+
resetScroll: kb.resetStatsScroll
|
|
1254
1370
|
}
|
|
1255
1371
|
),
|
|
1256
1372
|
kb.modal === "filter" && /* @__PURE__ */ jsx6(ServiceList, { title: "Filter by service", services: pm.states, onSelect: handleFilterSelect, onClose: () => kb.setModal("none") }),
|
|
@@ -1312,7 +1428,7 @@ ${formatValidationErrors(errors)}`);
|
|
|
1312
1428
|
}
|
|
1313
1429
|
const isInteractive = process.stdin.isTTY ?? false;
|
|
1314
1430
|
const { waitUntilExit } = render(
|
|
1315
|
-
|
|
1431
|
+
React6.createElement(App, {
|
|
1316
1432
|
config,
|
|
1317
1433
|
services,
|
|
1318
1434
|
cliArgs,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/config/loader.ts","../src/config/validator.ts","../src/config/cli.ts","../src/platform/detect.ts","../src/proxy-config/traefik.ts","../src/proxy-config/detect.ts","../src/utils.ts","../src/tui/App.tsx","../src/tui/hooks/useProcessManager.ts","../src/process/manager.ts","../src/process/health.ts","../src/process/installer.ts","../src/tui/hooks/useKeyBindings.ts","../src/tui/hooks/useProxySync.ts","../src/tui/LogsPanel.tsx","../src/tui/StatsPanel.tsx","../src/tui/StatusBar.tsx","../src/tui/ServiceList.tsx","../src/tui/SearchInput.tsx","../src/lazy/classifier.ts","../src/lazy/proxy.ts","../src/config/types.ts"],"sourcesContent":["import React from 'react';\nimport { render } from 'ink';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\n\nimport { findConfigFile, loadConfig } from './config/loader.js';\nimport { validateConfig, formatValidationErrors } from './config/validator.js';\nimport { parseCliArgs, filterServices } from './config/cli.js';\nimport { detectPlatform } from './platform/detect.js';\nimport { detectProxyProvider } from './proxy-config/detect.js';\nimport { parseEnvFile } from './utils.js';\nimport { App } from './tui/App.js';\nimport type { ProxyConfigProvider, ProxyOpts } from './proxy-config/types.js';\n\n// Re-export for config files\nexport { defineConfig } from './config/types.js';\nexport type { DevStackConfig, ServiceConfig, LazyConfig, ProxyConfig } from './config/types.js';\nexport type { Platform, ProcessStats } from './platform/types.js';\nexport type { ProxyConfigProvider, ProxyOpts } from './proxy-config/types.js';\n\nasync function main() {\n const cwd = process.cwd();\n const cliArgs = parseCliArgs(process.argv.slice(2));\n\n // Load config\n let configPath: string;\n try {\n configPath = findConfigFile(cwd, cliArgs.configPath);\n } catch (e: any) {\n console.error(`❌ ${e.message}`);\n process.exit(1);\n }\n\n const config = await loadConfig(configPath);\n\n // Validate\n const errors = validateConfig(config, cwd);\n if (errors.length) {\n console.error(`❌ Config validation failed:\\n${formatValidationErrors(errors)}`);\n process.exit(1);\n }\n\n // Filter services\n const services = filterServices(config.services, cliArgs);\n if (!services.length) {\n console.error('❌ No services to run after filtering');\n process.exit(1);\n }\n\n // Platform\n const platform = await detectPlatform();\n\n // Env\n const envFile = config.envFile ? join(cwd, config.envFile) : join(cwd, '.env');\n const env = parseEnvFile(envFile, process.env as Record<string, string>);\n if (config.env) {\n for (const [k, v] of Object.entries(config.env)) {\n if (!env[k]) env[k] = v;\n }\n }\n\n // Proxy provider\n let proxyProvider: ProxyConfigProvider | null = null;\n let proxyOpts: ProxyOpts | null = null;\n if (cliArgs.proxy && config.proxy) {\n proxyProvider = detectProxyProvider(config.proxy.provider);\n proxyOpts = {\n host: cliArgs.proxyHost ?? config.proxy.host ?? platform.defaultTraefikHost,\n domain: env['GUESTHUB_DOMAIN'] ?? env['DOMAIN'] ?? 'localhost',\n routes: config.proxy.routes,\n tls: cliArgs.proxyTls ?? config.proxy.tls ?? true,\n entrypoint: cliArgs.proxyEntrypoint ?? config.proxy.entrypoint ?? 'websecure',\n confPath: cliArgs.proxyConf ?? config.proxy.confPath ?? join(homedir(), '.traefik', 'traefik_conf.yaml'),\n };\n }\n\n // Render TUI\n const isInteractive = process.stdin.isTTY ?? false;\n const { waitUntilExit } = render(\n React.createElement(App, {\n config, services, cliArgs, platform, env, baseCwd: cwd,\n proxyProvider, proxyOpts,\n }),\n { exitOnCtrlC: false, patchConsole: isInteractive, interactive: isInteractive },\n );\n\n await waitUntilExit();\n}\n\nmain().catch(e => {\n console.error(e);\n process.exit(1);\n});\n","import { existsSync } from 'node:fs';\nimport { readFile } from 'node:fs/promises';\nimport { resolve, join } from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport type { DevStackConfig } from './types.js';\n\nconst CONFIG_NAMES = [\n 'devup.config.ts',\n 'devup.config.js',\n 'devup.config.json',\n];\n\nexport function findConfigFile(cwd: string, explicit?: string): string {\n if (explicit) {\n const full = resolve(cwd, explicit);\n if (!existsSync(full)) throw new Error(`Config not found: ${full}`);\n return full;\n }\n for (const name of CONFIG_NAMES) {\n const full = join(cwd, name);\n if (existsSync(full)) return full;\n }\n throw new Error(\n `No config found. Create one of: ${CONFIG_NAMES.join(', ')}\\n` +\n `Or use --config <path>`,\n );\n}\n\nexport async function loadConfig(configPath: string): Promise<DevStackConfig> {\n if (configPath.endsWith('.json')) {\n const raw = await readFile(configPath, 'utf8');\n return JSON.parse(raw) as DevStackConfig;\n }\n\n // .ts and .js — dynamic import (tsx loader handles .ts at runtime)\n const url = pathToFileURL(configPath).href;\n const mod = await import(url);\n const config = mod.default ?? mod;\n\n if (!config || typeof config !== 'object' || !Array.isArray(config.services)) {\n throw new Error(`Invalid config: must export a DevStackConfig (use defineConfig() from @gachlab/devup)`);\n }\n\n return config as DevStackConfig;\n}\n","import { existsSync } from 'node:fs';\nimport { resolve } from 'node:path';\nimport type { DevStackConfig } from './types.js';\n\nexport interface ValidationError {\n field: string;\n message: string;\n}\n\nexport function validateConfig(config: DevStackConfig, cwd: string): ValidationError[] {\n const errors: ValidationError[] = [];\n\n if (!config.name?.trim()) {\n errors.push({ field: 'name', message: 'Project name is required' });\n }\n\n if (!config.services?.length) {\n errors.push({ field: 'services', message: 'At least one service is required' });\n return errors;\n }\n\n // Unique names\n const names = new Set<string>();\n for (const svc of config.services) {\n if (names.has(svc.name)) {\n errors.push({ field: `services[${svc.name}].name`, message: `Duplicate service name: ${svc.name}` });\n }\n names.add(svc.name);\n }\n\n // Unique ports\n const ports = new Map<number, string>();\n for (const svc of config.services) {\n const existing = ports.get(svc.port);\n if (existing) {\n errors.push({ field: `services[${svc.name}].port`, message: `Port ${svc.port} already used by ${existing}` });\n }\n ports.set(svc.port, svc.name);\n }\n\n // Valid fields per service\n for (const svc of config.services) {\n if (!svc.name?.trim()) errors.push({ field: 'services[].name', message: 'Service name is required' });\n if (!svc.cwd?.trim()) errors.push({ field: `services[${svc.name}].cwd`, message: 'cwd is required' });\n if (!svc.cmd?.trim()) errors.push({ field: `services[${svc.name}].cmd`, message: 'cmd is required' });\n if (!svc.type || !['api', 'web'].includes(svc.type)) {\n errors.push({ field: `services[${svc.name}].type`, message: `Invalid type: ${svc.type} (must be \"api\" or \"web\")` });\n }\n if (typeof svc.port !== 'number' || svc.port <= 0) {\n errors.push({ field: `services[${svc.name}].port`, message: `Invalid port: ${svc.port}` });\n }\n if (typeof svc.phase !== 'number' || svc.phase < 0) {\n errors.push({ field: `services[${svc.name}].phase`, message: `Invalid phase: ${svc.phase}` });\n }\n\n // cwd exists\n if (svc.cwd && !existsSync(resolve(cwd, svc.cwd))) {\n errors.push({ field: `services[${svc.name}].cwd`, message: `Directory not found: ${svc.cwd}` });\n }\n }\n\n // Lazy refs\n if (config.lazy?.alwaysOn) {\n for (const ref of config.lazy.alwaysOn) {\n if (!names.has(ref)) {\n errors.push({ field: `lazy.alwaysOn`, message: `Unknown service: ${ref}` });\n }\n }\n }\n\n // Proxy route refs\n if (config.proxy?.routes) {\n for (const ref of Object.keys(config.proxy.routes)) {\n if (!names.has(ref)) {\n errors.push({ field: `proxy.routes`, message: `Unknown service: ${ref}` });\n }\n }\n }\n\n return errors;\n}\n\nexport function formatValidationErrors(errors: ValidationError[]): string {\n return errors.map(e => ` ✗ ${e.field}: ${e.message}`).join('\\n');\n}\n","import type { ServiceConfig } from './types.js';\n\nexport interface CliArgs {\n configPath?: string;\n only?: string;\n skip: string[];\n services?: string[];\n lazy: boolean;\n lazyTimeout: number;\n proxy: boolean;\n proxyHost?: string;\n proxyConf?: string;\n proxyTls: boolean;\n proxyEntrypoint: string;\n}\n\nconst DEFAULT_LAZY_TIMEOUT = 10;\n\nexport function parseCliArgs(argv: string[]): CliArgs {\n const args: CliArgs = {\n skip: [],\n lazy: true,\n lazyTimeout: DEFAULT_LAZY_TIMEOUT,\n proxy: false,\n proxyTls: true,\n proxyEntrypoint: 'websecure',\n };\n\n for (let i = 0; i < argv.length; i++) {\n const arg = argv[i]!;\n const next = argv[i + 1];\n\n switch (arg) {\n case '--config': args.configPath = next; i++; break;\n case '--only': args.only = next; i++; break;\n case '--skip': args.skip = next?.split(',') ?? []; i++; break;\n case '--services': args.services = next?.split(','); i++; break;\n case '--lazy': args.lazy = true; break;\n case '--no-lazy': args.lazy = false; break;\n case '--timeout': args.lazyTimeout = parseInt(next ?? '', 10) || DEFAULT_LAZY_TIMEOUT; i++; break;\n case '--proxy': args.proxy = true; break;\n case '--proxy-host': args.proxyHost = next; i++; break;\n case '--proxy-conf': args.proxyConf = next; i++; break;\n case '--proxy-tls': args.proxyTls = true; break;\n case '--no-proxy-tls': args.proxyTls = false; break;\n case '--proxy-entrypoint': args.proxyEntrypoint = next ?? 'websecure'; i++; break;\n }\n }\n\n return args;\n}\n\nexport function filterServices(services: ServiceConfig[], args: CliArgs): ServiceConfig[] {\n let result = services;\n\n if (args.services) {\n const explicit = new Set(args.services);\n result = result.filter(s => explicit.has(s.name));\n } else if (args.only) {\n switch (args.only) {\n case 'apis': result = result.filter(s => s.type === 'api'); break;\n case 'webs': result = result.filter(s => s.type === 'web'); break;\n default: result = result.filter(s => s.name.startsWith(args.only!)); break;\n }\n }\n\n if (args.skip.length) {\n const skipSet = new Set(args.skip);\n result = result.filter(s => !skipSet.has(s.name));\n }\n\n return result;\n}\n","import type { Platform } from './types.js';\n\nexport async function detectPlatform(): Promise<Platform> {\n switch (process.platform) {\n case 'linux': {\n const { LinuxPlatform } = await import('./linux.js');\n return new LinuxPlatform();\n }\n case 'darwin': {\n const { DarwinPlatform } = await import('./darwin.js');\n return new DarwinPlatform();\n }\n case 'win32': {\n const { Win32Platform } = await import('./win32.js');\n return new Win32Platform();\n }\n default:\n throw new Error(`Unsupported platform: ${process.platform}`);\n }\n}\n","import { existsSync, mkdirSync, writeFileSync } from 'node:fs';\nimport { dirname } from 'node:path';\nimport type { ProxyConfigProvider, ProxyOpts, ServiceState } from './types.js';\n\nconst EMPTY_CONFIG = 'http:\\n routers: {}\\n services: {}\\n';\n\nexport class TraefikProvider implements ProxyConfigProvider {\n readonly name = 'traefik';\n\n generate(services: Map<string, ServiceState>, opts: ProxyOpts): string {\n const routers: string[] = [];\n const svcs: string[] = [];\n\n for (const [name, st] of services) {\n if (st.health !== 'up') continue;\n const sub = opts.routes[name];\n if (sub === undefined) continue;\n\n const rule = sub ? `Host(\\`${sub}.${opts.domain}\\`)` : `Host(\\`${opts.domain}\\`)`;\n const safe = name.replace(/[^a-z0-9-]/g, '-');\n const port = st.realPort ?? st.port;\n\n let router = ` ${safe}:\\n rule: \"${rule}\"\\n service: ${safe}\\n entryPoints:\\n - ${opts.entrypoint}`;\n if (opts.tls) router += `\\n tls:\\n certResolver: le`;\n routers.push(router);\n\n svcs.push(` ${safe}:\\n loadBalancer:\\n servers:\\n - url: \"http://${opts.host}:${port}\"`);\n }\n\n if (!routers.length) return EMPTY_CONFIG;\n return `http:\\n routers:\\n${routers.join('\\n')}\\n services:\\n${svcs.join('\\n')}\\n`;\n }\n\n write(content: string, opts: ProxyOpts): void {\n const dir = dirname(opts.confPath);\n if (!existsSync(dir)) mkdirSync(dir, { recursive: true });\n writeFileSync(opts.confPath, content);\n }\n\n clear(opts: ProxyOpts): void {\n this.write(EMPTY_CONFIG, opts);\n }\n}\n","import type { ProxyConfigProvider } from './types.js';\nimport { TraefikProvider } from './traefik.js';\n\nconst providers: Record<string, () => ProxyConfigProvider> = {\n traefik: () => new TraefikProvider(),\n};\n\nexport function detectProxyProvider(name: string): ProxyConfigProvider {\n const factory = providers[name];\n if (!factory) {\n const available = Object.keys(providers).join(', ');\n throw new Error(`Unknown proxy provider: \"${name}\". Available: ${available}`);\n }\n return factory();\n}\n","import { existsSync, readFileSync, writeFileSync } from 'node:fs';\nimport { createHash } from 'node:crypto';\nimport { join } from 'node:path';\nimport type { ServiceConfig } from './config/types.js';\n\n// ── .env parsing ──\n\nexport function parseEnvFile(filePath: string, baseEnv: Record<string, string> = {}): Record<string, string> {\n const env = { ...baseEnv };\n if (!existsSync(filePath)) return env;\n\n for (const line of readFileSync(filePath, 'utf8').split('\\n')) {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith('#')) continue;\n const eqIdx = trimmed.indexOf('=');\n if (eqIdx === -1) continue;\n const key = trimmed.slice(0, eqIdx).trim();\n let val = trimmed.slice(eqIdx + 1).trim();\n if ((val.startsWith('\"') && val.endsWith('\"')) || (val.startsWith(\"'\") && val.endsWith(\"'\"))) {\n val = val.slice(1, -1);\n }\n if (!env[key]) env[key] = val;\n }\n return env;\n}\n\n// ── Format helpers ──\n\nexport function fmtUptime(ms: number): string {\n if (!ms || ms < 0) return '-';\n const s = Math.floor(ms / 1000);\n if (s < 60) return `${s}s`;\n const m = Math.floor(s / 60);\n if (m < 60) return `${m}m${s % 60}s`;\n const h = Math.floor(m / 60);\n return `${h}h${m % 60}m`;\n}\n\n// ── Search / highlight ──\n\nexport function highlightSearch(text: string, term: string | null, escapeFn?: (s: string) => string): string {\n const escaped = escapeFn ? escapeFn(text) : text;\n if (!term) return escaped;\n const idx = escaped.toLowerCase().indexOf(term.toLowerCase());\n if (idx === -1) return escaped;\n return `${escaped.slice(0, idx)}{black-fg}{yellow-bg}${escaped.slice(idx, idx + term.length)}{/yellow-bg}{/black-fg}${escaped.slice(idx + term.length)}`;\n}\n\nexport function findSearchMatch(\n lines: string[], term: string, currentScroll: number,\n direction: 'next' | 'prev', stripTagsFn?: (s: string) => string,\n): number {\n if (!term || !lines.length) return -1;\n const lower = term.toLowerCase();\n const len = lines.length;\n const start = direction === 'next' ? currentScroll + 1 : currentScroll - 1;\n for (let i = 0; i < len; i++) {\n const idx = direction === 'next' ? (start + i) % len : (start - i + len) % len;\n const raw = stripTagsFn ? stripTagsFn(lines[idx] ?? '') : (lines[idx] ?? '');\n if (raw.toLowerCase().includes(lower)) return idx;\n }\n return -1;\n}\n\n// ── Log formatting ──\n\nexport function formatLogLine(\n svcName: string, line: string, colorTag: string, maxNameLen: number,\n showTimestamps: boolean, searchTerm: string | null, escapeFn?: (s: string) => string,\n): string {\n const padded = svcName.padEnd(maxNameLen);\n const ts = showTimestamps ? `{#666666-fg}[${new Date().toLocaleTimeString('en-GB')}]{/#666666-fg} ` : '';\n const highlighted = highlightSearch(line, searchTerm, escapeFn);\n return `${ts}{${colorTag}-fg}[${padded}]{/${colorTag}-fg} ${highlighted}`;\n}\n\nexport function shouldLogLine(svcName: string, filter: string | null): boolean {\n return !filter || filter === svcName;\n}\n\nexport function buildLogsLabel(filter: string | null, searchTerm: string | null, paused: boolean): string {\n const parts = [' {bold}Logs{/bold}'];\n if (filter) parts.push(`[${filter}]`);\n if (searchTerm) parts.push(`{yellow-fg}/${searchTerm}{/yellow-fg}`);\n if (paused) parts.push('{red-fg}[PAUSED]{/red-fg}');\n return parts.join(' ') + ' ';\n}\n\n// ── npm install stamps ──\n\nexport function needsInstall(fullCwd: string): boolean {\n const nm = join(fullCwd, 'node_modules');\n if (!existsSync(nm)) return true;\n try {\n const pkgHash = createHash('md5').update(readFileSync(join(fullCwd, 'package.json'))).digest('hex');\n const stampFile = join(nm, '.install-stamp');\n if (existsSync(stampFile) && readFileSync(stampFile, 'utf8') === pkgHash) return false;\n } catch { /* stamp missing or unreadable */ }\n return true;\n}\n\nexport function writeInstallStamp(fullCwd: string): void {\n try {\n const pkgHash = createHash('md5').update(readFileSync(join(fullCwd, 'package.json'))).digest('hex');\n writeFileSync(join(fullCwd, 'node_modules', '.install-stamp'), pkgHash);\n } catch { /* best effort */ }\n}\n\n// ── Sort helpers ──\n\nexport function sortServiceNames(\n names: string[], sortMode: string,\n statsMap: Record<string, { cpu?: string; mem?: string }>,\n procState: Record<string, { errors?: number }>,\n): string[] {\n if (sortMode === 'name') return names.slice().sort();\n return names.slice().sort((a, b) => {\n if (sortMode === 'mem') {\n return (parseFloat(statsMap[b]?.mem ?? '0') || 0) - (parseFloat(statsMap[a]?.mem ?? '0') || 0);\n }\n return (procState[b]?.errors ?? 0) - (procState[a]?.errors ?? 0);\n });\n}\n\n// ── Phase grouping ──\n\nexport function groupByPhase(services: ServiceConfig[]): Record<number, ServiceConfig[]> {\n const phases: Record<number, ServiceConfig[]> = {};\n for (const s of services) {\n (phases[s.phase] ??= []).push(s);\n }\n return phases;\n}\n\n// ── Process args / env builders ──\n\nexport function buildProcessArgs(svc: ServiceConfig): string[] {\n const extra = svc.nodeArgs ?? [];\n if (!svc.maxMem) return [...extra, ...svc.args];\n if (svc.cmd === 'node') return [`--max-old-space-size=${svc.maxMem}`, ...extra, ...svc.args];\n return [...extra, ...svc.args];\n}\n\nexport function buildProcessEnv(svc: ServiceConfig, baseEnv: Record<string, string>): Record<string, string> {\n const env = { ...baseEnv, ...(svc.extraEnv ?? {}) };\n if (svc.maxMem && svc.cmd !== 'node') {\n const existing = env['NODE_OPTIONS'] ?? '';\n const flag = `--max-old-space-size=${svc.maxMem}`;\n if (!existing.includes('max-old-space-size')) {\n env['NODE_OPTIONS'] = existing ? `${existing} ${flag}` : flag;\n }\n }\n return env;\n}\n\n// ── CPU percent calculation ──\n\nexport function calcCpuPercent(totalCpuSec: number, prevCpu: number, prevTime: number): number {\n const elapsed = (Date.now() - prevTime) / 1000;\n const cpuDelta = totalCpuSec - prevCpu;\n return elapsed > 0 ? (cpuDelta / elapsed) * 100 : 0;\n}\n\n// ── Color palette ──\n\nexport const tagColors = [\n 'cyan', 'yellow', 'green', 'magenta', 'blue',\n 'red', '#5faf5f', '#d7af5f', '#5f87d7', '#af5faf',\n '#5fd7d7', '#d75f5f', 'white',\n];\n","import React, { useEffect, useState, useCallback, useRef } from 'react';\nimport { Box, Text, useStdout } from 'ink';\nimport type { Platform } from '../platform/types.js';\nimport type { DevStackConfig, ServiceConfig } from '../config/types.js';\nimport type { CliArgs } from '../config/cli.js';\nimport type { ProxyConfigProvider, ProxyOpts } from '../proxy-config/types.js';\nimport { useProcessManager } from './hooks/useProcessManager.js';\nimport { useKeyBindings } from './hooks/useKeyBindings.js';\nimport { useProxySync } from './hooks/useProxySync.js';\nimport { LogsPanel } from './LogsPanel.js';\nimport { StatsPanel } from './StatsPanel.js';\nimport { StatusBar } from './StatusBar.js';\nimport { ServiceList } from './ServiceList.js';\nimport { SearchInput } from './SearchInput.js';\nimport { groupByPhase } from '../utils.js';\nimport { waitForPort } from '../process/health.js';\nimport { classifyServices, rewriteServicePort } from '../lazy/classifier.js';\nimport { createLazyProxy, type LazyProxy } from '../lazy/proxy.js';\nimport type { ProcessState } from '../process/types.js';\n\ninterface Props {\n config: DevStackConfig;\n services: ServiceConfig[];\n cliArgs: CliArgs;\n platform: Platform;\n env: Record<string, string>;\n baseCwd: string;\n proxyProvider: ProxyConfigProvider | null;\n proxyOpts: ProxyOpts | null;\n}\n\nexport function App({ config, services, cliArgs, platform, env, baseCwd, proxyProvider, proxyOpts }: Props) {\n const { stdout } = useStdout();\n const rows = stdout?.rows ?? 40;\n const logsHeight = Math.floor(rows * 0.65);\n const statsHeight = rows - logsHeight - 2; // 2 for header + statusbar\n const maxNameLen = Math.max(...services.map(s => s.name.length), 10);\n\n const pm = useProcessManager(platform, baseCwd, env);\n const [booted, setBooted] = useState(false);\n const lazyProxies = useRef<Map<string, LazyProxy>>(new Map());\n\n const kb = useKeyBindings({\n onQuit: () => {\n lazyProxies.current.forEach(p => p.destroy());\n pm.cleanup();\n process.exit(0);\n },\n onClearLogs: () => {},\n onToggleProxy: () => {},\n });\n\n useProxySync(proxyProvider, proxyOpts, pm.states, kb.proxyEnabled);\n\n // Boot sequence\n useEffect(() => {\n if (booted || !pm.manager) return;\n setBooted(true);\n const mgr = pm.manager;\n\n (async () => {\n const lazyMode = cliArgs.lazy;\n const lazyTimeout = cliArgs.lazyTimeout;\n\n if (lazyMode && config.lazy) {\n // ── Lazy mode ──\n const { alwaysOn, lazy } = classifyServices(services, config.lazy);\n\n // Boot always-on services normally\n const aoPhases = groupByPhase(alwaysOn);\n let colorIdx = 0;\n for (const num of Object.keys(aoPhases).map(Number).sort((a, b) => a - b)) {\n const svcs = aoPhases[num]!;\n for (const svc of svcs) {\n await mgr.install(svc);\n await mgr.start(svc, colorIdx++);\n }\n const apis = svcs.filter(s => s.type === 'api');\n if (apis.length) await Promise.all(apis.map(s => waitForPort(s.port, { timeout: 45000 })));\n svcs.filter(s => s.type === 'web').forEach(s => {\n const st = mgr.state.get(s.name);\n if (st) st.status = 'running';\n });\n }\n\n // Set up lazy proxies\n for (const svc of lazy) {\n const ci = colorIdx++;\n const rewritten = rewriteServicePort(svc);\n\n // Register as idle in process state\n const idleState: ProcessState = {\n svc: rewritten, proc: null, pid: null,\n status: 'idle', health: 'idle',\n errors: 0, restarts: 0, startedAt: null,\n intentionalStop: false, colorIdx: ci,\n };\n mgr.state.set(svc.name, idleState);\n\n const proxy = createLazyProxy({\n listenPort: svc.port,\n targetPort: rewritten.realPort,\n timeoutMin: lazyTimeout,\n onDemandStart: async () => {\n await mgr.install(rewritten);\n await mgr.start(rewritten, ci);\n const ok = await waitForPort(rewritten.realPort, { timeout: 45000 });\n const st = mgr.state.get(svc.name);\n if (st) {\n st.status = ok ? 'running' : 'timeout';\n if (ok) st.health = 'up';\n }\n },\n onIdleStop: () => {\n mgr.stop(svc.name);\n const st = mgr.state.get(svc.name);\n if (st) { st.status = 'idle'; st.health = 'idle'; st.pid = null; st.proc = null; st.startedAt = null; }\n },\n isAlive: () => {\n const st = mgr.state.get(svc.name);\n return !!st && !!st.proc && !st.proc.killed && st.health === 'up';\n },\n });\n\n lazyProxies.current.set(svc.name, proxy);\n }\n } else {\n // ── Normal mode ──\n const phases = groupByPhase(services);\n let colorIdx = 0;\n for (const num of Object.keys(phases).map(Number).sort((a, b) => a - b)) {\n const svcs = phases[num]!;\n for (const svc of svcs) {\n await mgr.install(svc);\n await mgr.start(svc, colorIdx++);\n }\n const apis = svcs.filter(s => s.type === 'api');\n if (apis.length) await Promise.all(apis.map(s => waitForPort(s.port, { timeout: 45000 })));\n svcs.filter(s => s.type === 'web').forEach(s => {\n const st = mgr.state.get(s.name);\n if (st) st.status = 'running';\n });\n }\n }\n })();\n }, [booted, pm.manager, services, cliArgs, config.lazy]);\n\n const handleFilterSelect = useCallback((name: string) => kb.setFilter(name), [kb]);\n const handleRestartSelect = useCallback((name: string) => { pm.restart(name); kb.setModal('none'); }, [pm, kb]);\n const handleOpenSelect = useCallback((name: string) => {\n const st = pm.states.get(name);\n if (st) platform.openBrowser(`http://localhost:${st.svc.port}`);\n kb.setModal('none');\n }, [pm, platform, kb]);\n\n const icon = config.icon ?? '📦';\n const modeLabel = cliArgs.lazy && config.lazy ? 'lazy' : 'normal';\n\n return (\n <Box flexDirection=\"column\" height={rows}>\n <Box><Text bold color=\"cyan\"> {icon} {config.name} — devup — {services.length} services ({modeLabel}) </Text></Box>\n\n <LogsPanel\n logs={pm.logs} filter={kb.logFilter} searchTerm={kb.searchTerm}\n paused={kb.logsPaused} showTimestamps={kb.showTimestamps}\n maxNameLen={maxNameLen} height={logsHeight} focused={kb.panel === 'logs'}\n />\n\n <StatsPanel\n states={pm.states} stats={pm.stats} sortMode={kb.sortMode}\n maxNameLen={maxNameLen} height={statsHeight} focused={kb.panel === 'stats'}\n />\n\n {kb.modal === 'filter' && (\n <ServiceList title=\"Filter by service\" services={pm.states} onSelect={handleFilterSelect} onClose={() => kb.setModal('none')} />\n )}\n {kb.modal === 'restart' && (\n <ServiceList title=\"Restart service\" services={pm.states} onSelect={handleRestartSelect} onClose={() => kb.setModal('none')} />\n )}\n {kb.modal === 'open' && (\n <ServiceList title=\"Open in browser\" services={pm.states} onSelect={handleOpenSelect} onClose={() => kb.setModal('none')} filterType=\"web\" />\n )}\n {kb.modal === 'search' && (\n <SearchInput onSubmit={kb.setSearch} onClose={() => kb.setModal('none')} />\n )}\n\n <StatusBar />\n </Box>\n );\n}\n","import { useState, useEffect, useRef, useCallback } from 'react';\nimport { ProcessManager } from '../../process/manager.js';\nimport type { ProcessState } from '../../process/types.js';\nimport type { Platform } from '../../platform/types.js';\nimport type { ServiceConfig } from '../../config/types.js';\nimport { calcCpuPercent, tagColors } from '../../utils.js';\n\nexport interface LogEntry {\n svcName: string;\n text: string;\n colorIdx: number;\n ts: number;\n}\n\nexport interface ServiceStats {\n cpu: string;\n mem: string;\n}\n\nexport function useProcessManager(platform: Platform, baseCwd: string, env: Record<string, string>) {\n const [states, setStates] = useState<Map<string, ProcessState>>(new Map());\n const [logs, setLogs] = useState<LogEntry[]>([]);\n const [stats, setStats] = useState<Map<string, ServiceStats>>(new Map());\n const mgrRef = useRef<ProcessManager | null>(null);\n const prevCpu = useRef<Map<string, { time: number; cpu: number }>>(new Map());\n\n useEffect(() => {\n const mgr = new ProcessManager({\n baseCwd, env, platform,\n events: {\n onLog: (svcName, text, colorIdx) => {\n const lines = text.split('\\n').filter(Boolean);\n setLogs(prev => {\n const next = [...prev, ...lines.map(l => ({ svcName, text: l, colorIdx, ts: Date.now() }))];\n return next.length > 5000 ? next.slice(-5000) : next;\n });\n },\n onStateChange: () => setStates(new Map(mgr.state)),\n },\n });\n mgrRef.current = mgr;\n return () => { mgr.cleanup(); };\n }, [baseCwd, env, platform]);\n\n // Health + stats polling\n useEffect(() => {\n const id = setInterval(async () => {\n const mgr = mgrRef.current;\n if (!mgr) return;\n await mgr.checkAllHealth();\n setStates(new Map(mgr.state));\n\n const pids: number[] = [];\n const pidMap = new Map<number, string>();\n for (const [name, st] of mgr.state) {\n if (st.pid) { pids.push(st.pid); pidMap.set(st.pid, name); }\n }\n if (pids.length) {\n const raw = await platform.getProcessStats(pids);\n const next = new Map<string, ServiceStats>();\n for (const [pid, data] of raw) {\n const name = pidMap.get(pid);\n if (!name) continue;\n const prev = prevCpu.current.get(name) ?? { time: Date.now(), cpu: 0 };\n const cpuPct = calcCpuPercent(data.cpuSeconds, prev.cpu, prev.time);\n prevCpu.current.set(name, { time: Date.now(), cpu: data.cpuSeconds });\n next.set(name, { cpu: cpuPct.toFixed(1) + '%', mem: (data.rss / 1024).toFixed(1) + ' MB' });\n }\n setStats(next);\n }\n }, 3000);\n return () => clearInterval(id);\n }, [platform]);\n\n const mgr = mgrRef.current;\n\n return {\n states, logs, stats,\n start: useCallback((svc: ServiceConfig, colorIdx: number) => mgr?.start(svc, colorIdx), [mgr]),\n stop: useCallback((name: string) => mgr?.stop(name), [mgr]),\n restart: useCallback((name: string) => mgr?.restart(name), [mgr]),\n install: useCallback((svc: ServiceConfig) => mgr?.install(svc), [mgr]),\n cleanup: useCallback(() => mgr?.cleanup(), [mgr]),\n manager: mgr,\n };\n}\n","import { spawn } from 'node:child_process';\nimport { join } from 'node:path';\nimport type { ChildProcess } from 'node:child_process';\nimport type { Platform } from '../platform/types.js';\nimport type { ServiceConfig } from '../config/types.js';\nimport type { ProcessState, ProcessManagerEvents } from './types.js';\nimport { checkPort, deriveHealth } from './health.js';\nimport { installService } from './installer.js';\nimport { buildProcessArgs, buildProcessEnv } from '../utils.js';\n\nconst MAX_RESTARTS = 3;\nconst BACKOFF_BASE_MS = 2000;\n\nexport class ProcessManager {\n readonly state = new Map<string, ProcessState>();\n private readonly procs = new Set<ChildProcess>();\n private readonly baseCwd: string;\n private readonly env: Record<string, string>;\n private readonly platform: Platform;\n private readonly events: ProcessManagerEvents;\n\n constructor(opts: {\n baseCwd: string;\n env: Record<string, string>;\n platform: Platform;\n events: ProcessManagerEvents;\n }) {\n this.baseCwd = opts.baseCwd;\n this.env = opts.env;\n this.platform = opts.platform;\n this.events = opts.events;\n }\n\n async install(svc: ServiceConfig): Promise<boolean> {\n const cwd = join(this.baseCwd, svc.cwd);\n return installService(cwd, this.env, msg => this.log(svc.name, msg, this.getColorIdx(svc.name)));\n }\n\n async start(svc: ServiceConfig, colorIdx: number, isRestart = false): Promise<void> {\n const cwd = join(this.baseCwd, svc.cwd);\n\n // Port occupied check\n if (svc.type === 'api') {\n const occupied = await checkPort(svc.port);\n if (occupied && !isRestart) {\n this.log(svc.name, `⚠ port ${svc.port} already in use — skipping`, colorIdx);\n return;\n }\n }\n\n const args = buildProcessArgs(svc);\n const env = buildProcessEnv(svc, this.env);\n const proc = spawn(svc.cmd, args, { cwd, env, detached: true, stdio: ['ignore', 'pipe', 'pipe'] });\n\n const prev = this.state.get(svc.name);\n const state: ProcessState = {\n svc, proc, pid: proc.pid ?? null,\n status: 'starting', health: 'wait',\n errors: prev?.errors ?? 0,\n restarts: prev?.restarts ?? 0,\n startedAt: Date.now(),\n intentionalStop: false,\n colorIdx,\n };\n this.state.set(svc.name, state);\n this.procs.add(proc);\n this.events.onStateChange(svc.name, state);\n\n proc.stdout?.on('data', (d: Buffer) => this.log(svc.name, d.toString(), colorIdx));\n proc.stderr?.on('data', (d: Buffer) => {\n state.errors += d.toString().split('\\n').filter(Boolean).length;\n this.log(svc.name, d.toString(), colorIdx);\n });\n\n proc.on('close', code => {\n this.procs.delete(proc);\n if (state.intentionalStop) { state.intentionalStop = false; return; }\n if (code === 0) {\n state.status = 'stopped'; state.health = 'down';\n this.events.onStateChange(svc.name, state);\n return;\n }\n state.status = 'crashed'; state.health = 'down';\n this.log(svc.name, `❌ exited with code ${code}`, colorIdx);\n this.events.onStateChange(svc.name, state);\n\n if (state.restarts < MAX_RESTARTS) {\n state.restarts++;\n const delay = BACKOFF_BASE_MS * Math.pow(2, state.restarts - 1);\n this.log(svc.name, `🔄 auto-restart ${state.restarts}/${MAX_RESTARTS} in ${delay}ms...`, colorIdx);\n setTimeout(() => this.start(svc, colorIdx, true), delay);\n } else {\n this.log(svc.name, '⛔ max restarts reached', colorIdx);\n }\n });\n\n this.log(svc.name, isRestart ? `🔄 restarted (:${svc.port})` : `🚀 started (:${svc.port})`, colorIdx);\n }\n\n stop(name: string): void {\n const st = this.state.get(name);\n if (!st?.proc || !st.pid) return;\n st.intentionalStop = true;\n this.platform.killTree(st.pid);\n }\n\n async restart(name: string): Promise<void> {\n const st = this.state.get(name);\n if (!st) return;\n this.stop(name);\n st.restarts++;\n const delay = st.proc ? 1500 : 100;\n await new Promise(r => setTimeout(r, delay));\n await this.start(st.svc, st.colorIdx, true);\n this.log(name, '🔄 manual restart', st.colorIdx);\n }\n\n async checkAllHealth(): Promise<void> {\n for (const [name, st] of this.state) {\n if (!st.pid || st.status === 'idle') {\n st.health = st.status === 'idle' ? 'idle' : 'down';\n continue;\n }\n const port = st.svc.port;\n const isUp = await checkPort(port);\n const prev = st.health;\n st.health = deriveHealth(isUp, st.status);\n if (st.health === 'up' && st.status === 'starting') st.status = 'running';\n if (prev !== st.health) this.events.onStateChange(name, st);\n }\n }\n\n cleanup(): void {\n for (const proc of this.procs) {\n if (proc.pid) this.platform.killTree(proc.pid);\n }\n // Force kill after 3s\n setTimeout(() => {\n for (const proc of this.procs) {\n if (proc.pid) this.platform.killTree(proc.pid, 'SIGKILL');\n }\n }, 3000);\n }\n\n private log(name: string, text: string, colorIdx: number): void {\n this.events.onLog(name, text, colorIdx);\n }\n\n private getColorIdx(name: string): number {\n return this.state.get(name)?.colorIdx ?? 0;\n }\n}\n","import net from 'node:net';\nimport type { HealthStatus } from './types.js';\n\nexport function checkPort(port: number, host = '127.0.0.1'): Promise<boolean> {\n return new Promise(resolve => {\n const socket = new net.Socket();\n socket.setTimeout(2000);\n socket.once('connect', () => { socket.destroy(); resolve(true); });\n socket.once('error', () => { socket.destroy(); resolve(false); });\n socket.once('timeout', () => { socket.destroy(); resolve(false); });\n socket.connect(port, host);\n });\n}\n\nexport function waitForPort(port: number, opts: { timeout?: number; interval?: number } = {}): Promise<boolean> {\n const { timeout = 45000, interval = 1000 } = opts;\n return new Promise(resolve => {\n const start = Date.now();\n const check = () => {\n checkPort(port).then(ok => {\n if (ok) return resolve(true);\n if (Date.now() - start > timeout) return resolve(false);\n setTimeout(check, interval);\n });\n };\n check();\n });\n}\n\nexport function deriveHealth(isUp: boolean, currentStatus: string): HealthStatus {\n if (currentStatus === 'idle') return 'idle';\n if (isUp) return 'up';\n return currentStatus === 'starting' ? 'wait' : 'down';\n}\n","import { spawn } from 'node:child_process';\nimport { existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { needsInstall, writeInstallStamp } from '../utils.js';\n\nexport interface InstallResult {\n name: string;\n ok: boolean;\n error?: string;\n}\n\nexport function installService(\n cwd: string, env: Record<string, string>,\n onLog?: (msg: string) => void,\n): Promise<boolean> {\n if (!existsSync(cwd)) {\n onLog?.(`⚠ directory not found: ${cwd}`);\n return Promise.resolve(false);\n }\n if (!needsInstall(cwd)) {\n onLog?.('✅ dependencies up to date');\n return Promise.resolve(true);\n }\n onLog?.('📦 npm install...');\n return new Promise(resolve => {\n const proc = spawn('npm', ['install'], { cwd, env, stdio: ['ignore', 'ignore', 'pipe'] });\n let stderr = '';\n proc.stderr?.on('data', (d: Buffer) => { stderr += d.toString(); });\n proc.on('close', code => {\n if (code !== 0) {\n onLog?.(`⚠ npm install failed: ${stderr.split('\\n')[0]}`);\n resolve(false);\n } else {\n writeInstallStamp(cwd);\n onLog?.('✅ dependencies ready');\n resolve(true);\n }\n });\n });\n}\n\nexport async function installBatch(\n items: Array<{ name: string; cwd: string; env: Record<string, string> }>,\n concurrency: number,\n onLog?: (name: string, msg: string) => void,\n): Promise<InstallResult[]> {\n const results: InstallResult[] = [];\n const queue = [...items];\n const running: Promise<void>[] = [];\n\n while (queue.length > 0 || running.length > 0) {\n while (running.length < concurrency && queue.length > 0) {\n const item = queue.shift()!;\n const p = installService(item.cwd, item.env, msg => onLog?.(item.name, msg))\n .then(ok => {\n results.push({ name: item.name, ok });\n running.splice(running.indexOf(p), 1);\n });\n running.push(p);\n }\n if (running.length > 0) await Promise.race(running);\n }\n return results;\n}\n","import { useInput } from 'ink';\nimport { useState, useCallback } from 'react';\n\nexport type Modal = 'none' | 'filter' | 'restart' | 'open' | 'search';\nexport type Panel = 'logs' | 'stats';\n\nexport interface KeyState {\n panel: Panel;\n modal: Modal;\n logFilter: string | null;\n searchTerm: string | null;\n logsPaused: boolean;\n showTimestamps: boolean;\n sortIdx: number;\n proxyEnabled: boolean;\n}\n\nconst SORT_MODES = ['name', 'mem', 'errors'] as const;\n\nexport function useKeyBindings(opts: {\n onQuit: () => void;\n onClearLogs: () => void;\n onToggleProxy: () => void;\n}) {\n const [state, setState] = useState<KeyState>({\n panel: 'logs', modal: 'none', logFilter: null, searchTerm: null,\n logsPaused: false, showTimestamps: false, sortIdx: 0, proxyEnabled: false,\n });\n\n const setModal = useCallback((modal: Modal) => setState(s => ({ ...s, modal })), []);\n const setFilter = useCallback((f: string | null) => setState(s => ({ ...s, logFilter: f, modal: 'none' })), []);\n const setSearch = useCallback((t: string | null) => setState(s => ({ ...s, searchTerm: t, modal: 'none' })), []);\n\n const isActive = process.stdin.isTTY ?? false;\n\n useInput((input, key) => {\n if (state.modal !== 'none') return;\n\n if (input === 'q' || (key.ctrl && input === 'c')) opts.onQuit();\n else if (input === 'c') opts.onClearLogs();\n else if (key.tab) setState(s => ({ ...s, panel: s.panel === 'logs' ? 'stats' : 'logs' }));\n else if (input === 'f') setModal('filter');\n else if (input === 'r') setModal('restart');\n else if (input === 'o') setModal('open');\n else if (input === '/') setModal('search');\n else if (input === 'a') setState(s => ({ ...s, logFilter: null, searchTerm: null }));\n else if (input === 'p') setState(s => ({ ...s, logsPaused: !s.logsPaused }));\n else if (input === 't') setState(s => ({ ...s, showTimestamps: !s.showTimestamps }));\n else if (input === 's') setState(s => ({ ...s, sortIdx: (s.sortIdx + 1) % SORT_MODES.length }));\n else if (input === 'T') { opts.onToggleProxy(); setState(s => ({ ...s, proxyEnabled: !s.proxyEnabled })); }\n }, { isActive });\n\n return { ...state, setModal, setFilter, setSearch, sortMode: SORT_MODES[state.sortIdx]! };\n}\n","import { useEffect, useRef } from 'react';\nimport type { ProxyConfigProvider, ProxyOpts, ServiceState } from '../../proxy-config/types.js';\nimport type { ProcessState } from '../../process/types.js';\n\nexport function useProxySync(\n provider: ProxyConfigProvider | null,\n opts: ProxyOpts | null,\n states: Map<string, ProcessState>,\n enabled: boolean,\n) {\n const intervalRef = useRef<ReturnType<typeof setInterval> | null>(null);\n\n useEffect(() => {\n if (!provider || !opts || !enabled) {\n if (intervalRef.current) clearInterval(intervalRef.current);\n return;\n }\n\n const sync = () => {\n const svcStates = new Map<string, ServiceState>();\n for (const [name, st] of states) {\n svcStates.set(name, { port: st.svc.port, health: st.health, realPort: (st.svc as any).realPort });\n }\n const content = provider.generate(svcStates, opts);\n provider.write(content, opts);\n };\n\n sync();\n intervalRef.current = setInterval(sync, 3000);\n return () => { if (intervalRef.current) clearInterval(intervalRef.current); };\n }, [provider, opts, enabled, states]);\n}\n","import React from 'react';\nimport { Box, Text } from 'ink';\nimport type { LogEntry } from './hooks/useProcessManager.js';\nimport { tagColors } from '../utils.js';\n\ninterface Props {\n logs: LogEntry[];\n filter: string | null;\n searchTerm: string | null;\n paused: boolean;\n showTimestamps: boolean;\n maxNameLen: number;\n height: number;\n focused: boolean;\n}\n\nexport function LogsPanel({ logs, filter, searchTerm, paused, showTimestamps, maxNameLen, height, focused }: Props) {\n const filtered = filter ? logs.filter(l => l.svcName === filter) : logs;\n const contentHeight = height - 2;\n const visible = filtered.slice(-contentHeight);\n\n const label = [\n 'Logs',\n filter ? `[${filter}]` : '',\n searchTerm ? `/${searchTerm}` : '',\n paused ? '[PAUSED]' : '',\n `${filtered.length} lines`,\n ].filter(Boolean).join(' ');\n\n return (\n <Box flexDirection=\"column\" borderStyle=\"round\" borderColor={focused ? 'cyan' : 'gray'} height={height}>\n <Box><Text bold color=\"cyan\"> {label} </Text></Box>\n {visible.map((entry, i) => {\n const color = tagColors[entry.colorIdx % tagColors.length]!;\n const ts = showTimestamps ? new Date(entry.ts).toLocaleTimeString('en-GB') + ' ' : '';\n const line = entry.text;\n const isMatch = searchTerm && line.toLowerCase().includes(searchTerm.toLowerCase());\n return (\n <Box key={i}>\n {showTimestamps && <Text dimColor>{ts}</Text>}\n <Text color={color}>[{entry.svcName.padEnd(maxNameLen)}]</Text>\n <Text> </Text>\n {isMatch ? <Text backgroundColor=\"yellow\" color=\"black\">{line}</Text> : <Text>{line}</Text>}\n </Box>\n );\n })}\n </Box>\n );\n}\n","import React from 'react';\nimport { Box, Text } from 'ink';\nimport type { ProcessState } from '../process/types.js';\nimport type { ServiceStats } from './hooks/useProcessManager.js';\nimport { fmtUptime, sortServiceNames, tagColors } from '../utils.js';\nimport os from 'node:os';\n\ninterface Props {\n states: Map<string, ProcessState>;\n stats: Map<string, ServiceStats>;\n sortMode: string;\n maxNameLen: number;\n height: number;\n focused: boolean;\n}\n\nconst H: Record<string, { c: string; color: string }> = {\n up: { c: '●', color: 'green' }, wait: { c: '●', color: 'yellow' },\n down: { c: '●', color: 'red' }, idle: { c: '○', color: 'blue' },\n};\n\nfunction Row({ name, st, stat, ml }: { name: string; st: ProcessState; stat?: ServiceStats; ml: number }) {\n const h = H[st.health] ?? H['down']!;\n const color = tagColors[st.colorIdx % tagColors.length]!;\n const sc = st.status === 'running' ? 'green' : st.status === 'starting' ? 'yellow' : st.status === 'idle' ? 'blue' : 'red';\n const up = st.startedAt ? fmtUptime(Date.now() - st.startedAt) : '-';\n return (\n <Text>\n <Text color={h.color}>{h.c}</Text> <Text color={color}>{name.padEnd(ml)}</Text> {String(st.svc.port).padStart(5)} <Text color={sc}>{st.status.padEnd(8)}</Text> {(stat?.cpu ?? '-').padStart(6)} {(stat?.mem ?? '-').padStart(8)} {String(st.errors).padStart(3)} {String(st.restarts).padStart(3)} {up.padStart(6)}\n </Text>\n );\n}\n\nfunction ColHeader({ ml }: { ml: number }) {\n return <Text bold>H {'Service'.padEnd(ml)} {'Port'.padStart(5)} {'Status'.padEnd(8)} {'CPU'.padStart(6)} {'Mem'.padStart(8)} Err Rst {'Up'.padStart(6)}</Text>;\n}\n\nexport function StatsPanel({ states, stats, sortMode, maxNameLen, height, focused }: Props) {\n const names = [...states.keys()];\n const stObj = Object.fromEntries([...states].map(([k, v]) => [k, { errors: v.errors }]));\n const statsObj = Object.fromEntries([...stats].map(([k, v]) => [k, v]));\n\n const apis = sortServiceNames(names.filter(n => states.get(n)!.svc.type === 'api'), sortMode, statsObj, stObj);\n const webs = sortServiceNames(names.filter(n => states.get(n)!.svc.type === 'web'), sortMode, statsObj, stObj);\n\n // System stats\n const cpus = os.cpus().length;\n const totalGB = (os.totalmem() / 1024 / 1024 / 1024).toFixed(1);\n const usedGB = (parseFloat(totalGB) - os.freemem() / 1024 / 1024 / 1024).toFixed(1);\n const load = os.loadavg()[0]!.toFixed(2);\n\n // Stack totals\n let totalCpu = 0, totalMemMB = 0, totalErrors = 0, totalRestarts = 0;\n for (const name of names) {\n const s = stats.get(name);\n if (s) {\n const c = parseFloat(s.cpu); if (!isNaN(c)) totalCpu += c;\n const m = parseFloat(s.mem); if (!isNaN(m)) totalMemMB += m;\n }\n totalErrors += states.get(name)?.errors ?? 0;\n totalRestarts += states.get(name)?.restarts ?? 0;\n }\n const stackMem = totalMemMB >= 1024 ? (totalMemMB / 1024).toFixed(2) + ' GB' : totalMemMB.toFixed(1) + ' MB';\n\n const ml = maxNameLen;\n const contentHeight = height - 2;\n\n return (\n <Box flexDirection=\"column\" borderStyle=\"round\" borderColor={focused ? 'green' : 'gray'} height={height}>\n <Box>\n <Text bold color=\"green\"> Stats </Text>\n <Text dimColor>System: {cpus}c Load {load} RAM {usedGB}/{totalGB}GB</Text>\n <Text dimColor> │ </Text>\n <Text dimColor>Stack: CPU {totalCpu.toFixed(1)}% RAM {stackMem} Err {totalErrors} Rst {totalRestarts} Svcs {names.length}</Text>\n {sortMode !== 'name' && <Text dimColor> │ Sort: {sortMode}</Text>}\n </Box>\n <Box flexGrow={1}>\n {/* Left column: APIs */}\n <Box flexDirection=\"column\" flexGrow={1} flexBasis={0}>\n <Text bold color=\"cyan\"> APIs ({apis.length})</Text>\n <ColHeader ml={ml} />\n {apis.slice(0, contentHeight - 2).map(n => (\n <Row key={n} name={n} st={states.get(n)!} stat={stats.get(n)} ml={ml} />\n ))}\n </Box>\n {/* Separator */}\n <Box flexDirection=\"column\" width={1}>\n {Array.from({ length: contentHeight }, (_, i) => <Text key={i} dimColor>│</Text>)}\n </Box>\n {/* Right column: Webs */}\n <Box flexDirection=\"column\" flexGrow={1} flexBasis={0}>\n <Text bold color=\"magenta\"> Webs ({webs.length})</Text>\n <ColHeader ml={ml} />\n {webs.slice(0, contentHeight - 2).map(n => (\n <Row key={n} name={n} st={states.get(n)!} stat={stats.get(n)} ml={ml} />\n ))}\n </Box>\n </Box>\n </Box>\n );\n}\n","import React from 'react';\nimport { Box, Text } from 'ink';\n\nexport function StatusBar() {\n return (\n <Box>\n <Text>\n <Text bold>q</Text> Quit <Text bold>Tab</Text> Switch <Text bold>c</Text> Clear <Text bold>f</Text> Filter <Text bold>a</Text> All <Text bold>r</Text> Restart <Text bold>/</Text> Search <Text bold>s</Text> Sort <Text bold>o</Text> Open <Text bold>p</Text> Pause <Text bold>t</Text> Time <Text bold>T</Text> Proxy\n </Text>\n </Box>\n );\n}\n","import React, { useState } from 'react';\nimport { Box, Text, useInput } from 'ink';\nimport type { ProcessState } from '../process/types.js';\n\ninterface Props {\n title: string;\n services: Map<string, ProcessState>;\n onSelect: (name: string) => void;\n onClose: () => void;\n filterType?: 'api' | 'web';\n}\n\nexport function ServiceList({ title, services, onSelect, onClose, filterType }: Props) {\n const names = [...services.keys()].filter(n => !filterType || services.get(n)!.svc.type === filterType);\n const [idx, setIdx] = useState(0);\n\n useInput((input, key) => {\n if (key.escape) onClose();\n else if (key.return) { if (names[idx]) onSelect(names[idx]!); }\n else if (key.upArrow) setIdx(i => Math.max(0, i - 1));\n else if (key.downArrow) setIdx(i => Math.min(names.length - 1, i + 1));\n }, { isActive: process.stdin.isTTY ?? false });\n\n return (\n <Box flexDirection=\"column\" borderStyle=\"round\" borderColor=\"cyan\" paddingX={1}>\n <Text bold color=\"cyan\"> {title} </Text>\n {names.map((name, i) => (\n <Box key={name}>\n <Text color={i === idx ? 'cyan' : undefined} inverse={i === idx}> {name} :{services.get(name)!.svc.port} </Text>\n </Box>\n ))}\n <Text dimColor>↑↓ navigate Enter select Esc close</Text>\n </Box>\n );\n}\n","import React, { useState } from 'react';\nimport { Box, Text, useInput } from 'ink';\n\ninterface Props {\n onSubmit: (term: string | null) => void;\n onClose: () => void;\n}\n\nexport function SearchInput({ onSubmit, onClose }: Props) {\n const [value, setValue] = useState('');\n\n useInput((input, key) => {\n if (key.escape) onClose();\n else if (key.return) onSubmit(value.trim() || null);\n else if (key.backspace || key.delete) setValue(v => v.slice(0, -1));\n else if (input && !key.ctrl && !key.meta) setValue(v => v + input);\n }, { isActive: process.stdin.isTTY ?? false });\n\n return (\n <Box borderStyle=\"round\" borderColor=\"yellow\" paddingX={1}>\n <Text bold color=\"yellow\">Search: </Text>\n <Text>{value}</Text>\n <Text dimColor>█</Text>\n </Box>\n );\n}\n","import type { ServiceConfig, LazyConfig } from '../config/types.js';\n\nexport const LAZY_PORT_OFFSET = 10000;\nexport const DEFAULT_LAZY_TIMEOUT = 10;\n\nexport interface ClassifiedServices {\n alwaysOn: ServiceConfig[];\n lazy: ServiceConfig[];\n}\n\nexport function classifyServices(services: ServiceConfig[], config?: LazyConfig): ClassifiedServices {\n const alwaysOnSet = new Set(config?.alwaysOn ?? []);\n const alwaysOn: ServiceConfig[] = [];\n const lazy: ServiceConfig[] = [];\n\n for (const svc of services) {\n if (alwaysOnSet.has(svc.name)) alwaysOn.push(svc);\n else lazy.push(svc);\n }\n return { alwaysOn, lazy };\n}\n\nexport function getLazyRealPort(originalPort: number): number {\n return originalPort + LAZY_PORT_OFFSET;\n}\n\nexport function rewriteServicePort(svc: ServiceConfig): ServiceConfig & { realPort: number; originalPort: number } {\n const realPort = getLazyRealPort(svc.port);\n const args = svc.args.map(a => a === String(svc.port) ? String(realPort) : a);\n const extraEnv = { ...svc.extraEnv, PORT_OVERRIDE: String(realPort) };\n return { ...svc, port: realPort, args, extraEnv, realPort, originalPort: svc.port };\n}\n","import net from 'node:net';\nimport { waitForPort } from '../process/health.js';\n\nexport interface LazyProxyOpts {\n listenPort: number;\n targetPort: number;\n timeoutMin: number;\n onDemandStart: () => Promise<void>;\n onIdleStop: () => void;\n isAlive: () => boolean;\n onLog?: (msg: string) => void;\n}\n\nexport interface LazyProxy {\n server: net.Server;\n resetTimer: () => void;\n destroy: () => void;\n}\n\nexport function createLazyProxy(opts: LazyProxyOpts): LazyProxy {\n const { listenPort, targetPort, timeoutMin, onDemandStart, onIdleStop, isAlive, onLog } = opts;\n let idleTimer: ReturnType<typeof setTimeout> | null = null;\n let starting = false;\n let serviceReady = false;\n let pendingConns: net.Socket[] = [];\n\n function resetTimer() {\n if (idleTimer) clearTimeout(idleTimer);\n if (timeoutMin > 0) {\n idleTimer = setTimeout(() => {\n serviceReady = false;\n onLog?.(`💤 idle ${timeoutMin}min — stopping`);\n onIdleStop();\n }, timeoutMin * 60_000);\n }\n }\n\n function pipeToTarget(client: net.Socket) {\n const target = net.createConnection({ port: targetPort, host: '127.0.0.1', allowHalfOpen: true });\n target.on('error', () => { client.destroy(); });\n client.on('error', () => { target.destroy(); });\n target.on('connect', () => {\n target.on('data', (chunk) => { if (!client.destroyed) client.write(chunk); });\n client.on('data', (chunk) => { if (!target.destroyed) target.write(chunk); });\n target.on('end', () => { if (!client.destroyed) client.end(); });\n client.on('end', () => { if (!target.destroyed) target.end(); });\n });\n }\n\n async function handleConnection(client: net.Socket) {\n resetTimer();\n client.on('error', () => {}); // Prevent uncaught ECONNRESET\n\n if (serviceReady && isAlive()) {\n pipeToTarget(client);\n return;\n }\n\n pendingConns.push(client);\n client.on('close', () => { pendingConns = pendingConns.filter(s => s !== client); });\n\n if (starting) return;\n starting = true;\n\n onLog?.('⚡ on-demand start');\n try {\n await onDemandStart();\n const ok = await waitForPort(targetPort, { timeout: 45000, interval: 500 });\n if (ok) serviceReady = true;\n else onLog?.('⚠ timeout waiting for service');\n } catch (e: unknown) {\n onLog?.(`❌ start failed: ${(e as Error).message}`);\n }\n starting = false;\n\n const conns = pendingConns.splice(0);\n for (const conn of conns) {\n if (!conn.destroyed) pipeToTarget(conn);\n }\n }\n\n const server = net.createServer({ allowHalfOpen: true }, socket => handleConnection(socket));\n server.listen(listenPort, '0.0.0.0');\n resetTimer();\n\n return {\n server,\n resetTimer,\n destroy: () => {\n if (idleTimer) clearTimeout(idleTimer);\n pendingConns.forEach(s => s.destroy());\n server.close();\n },\n };\n}\n","export interface ServiceConfig {\n name: string;\n cwd: string;\n cmd: string;\n args: string[];\n type: 'api' | 'web';\n port: number;\n phase: number;\n maxMem?: number;\n preBuild?: string;\n watchBuild?: string;\n nodeArgs?: string[];\n extraEnv?: Record<string, string>;\n}\n\nexport interface LazyConfig {\n alwaysOn: string[];\n timeout?: number;\n}\n\nexport interface ProxyConfig {\n provider: string;\n routes: Record<string, string>;\n confPath?: string;\n host?: string;\n tls?: boolean;\n entrypoint?: string;\n}\n\nexport interface DevStackConfig {\n name: string;\n icon?: string;\n envFile?: string;\n env?: Record<string, string>;\n services: ServiceConfig[];\n lazy?: LazyConfig;\n proxy?: ProxyConfig;\n}\n\nexport function defineConfig(config: DevStackConfig): DevStackConfig {\n return config;\n}\n"],"mappings":"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","names":["React","join","existsSync","resolve","existsSync","existsSync","writeFileSync","join","join","existsSync","writeFileSync","useEffect","useState","useCallback","useRef","Box","Text","spawn","join","resolve","existsSync","existsSync","resolve","join","spawn","mgr","useState","useCallback","useEffect","useRef","Box","Text","jsx","jsxs","Text","Box","Box","Text","jsx","jsxs","useState","Box","Text","useInput","jsx","jsxs","useState","Box","Text","useInput","jsx","jsxs","net","net","jsx","jsxs","useState","useRef","useEffect","useCallback","Box","Text","join","React"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/config/loader.ts","../src/config/validator.ts","../src/config/cli.ts","../src/platform/detect.ts","../src/proxy-config/traefik.ts","../src/proxy-config/detect.ts","../src/utils.ts","../src/tui/App.tsx","../src/tui/hooks/useProcessManager.ts","../src/process/manager.ts","../src/process/health.ts","../src/process/installer.ts","../src/tui/hooks/useKeyBindings.ts","../src/tui/hooks/useProxySync.ts","../src/tui/LogsPanel.tsx","../src/tui/StatsPanel.tsx","../src/tui/StatusBar.tsx","../src/tui/ServiceList.tsx","../src/tui/SearchInput.tsx","../src/lazy/classifier.ts","../src/lazy/proxy.ts","../src/config/types.ts"],"sourcesContent":["import React from 'react';\nimport { render } from 'ink';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\n\nimport { findConfigFile, loadConfig } from './config/loader.js';\nimport { validateConfig, formatValidationErrors } from './config/validator.js';\nimport { parseCliArgs, filterServices } from './config/cli.js';\nimport { detectPlatform } from './platform/detect.js';\nimport { detectProxyProvider } from './proxy-config/detect.js';\nimport { parseEnvFile } from './utils.js';\nimport { App } from './tui/App.js';\nimport type { ProxyConfigProvider, ProxyOpts } from './proxy-config/types.js';\n\n// Re-export for config files\nexport { defineConfig } from './config/types.js';\nexport type { DevStackConfig, ServiceConfig, LazyConfig, ProxyConfig } from './config/types.js';\nexport type { Platform, ProcessStats } from './platform/types.js';\nexport type { ProxyConfigProvider, ProxyOpts } from './proxy-config/types.js';\n\nasync function main() {\n const cwd = process.cwd();\n const cliArgs = parseCliArgs(process.argv.slice(2));\n\n // Load config\n let configPath: string;\n try {\n configPath = findConfigFile(cwd, cliArgs.configPath);\n } catch (e: any) {\n console.error(`❌ ${e.message}`);\n process.exit(1);\n }\n\n const config = await loadConfig(configPath);\n\n // Validate\n const errors = validateConfig(config, cwd);\n if (errors.length) {\n console.error(`❌ Config validation failed:\\n${formatValidationErrors(errors)}`);\n process.exit(1);\n }\n\n // Filter services\n const services = filterServices(config.services, cliArgs);\n if (!services.length) {\n console.error('❌ No services to run after filtering');\n process.exit(1);\n }\n\n // Platform\n const platform = await detectPlatform();\n\n // Env\n const envFile = config.envFile ? join(cwd, config.envFile) : join(cwd, '.env');\n const env = parseEnvFile(envFile, process.env as Record<string, string>);\n if (config.env) {\n for (const [k, v] of Object.entries(config.env)) {\n if (!env[k]) env[k] = v;\n }\n }\n\n // Proxy provider\n let proxyProvider: ProxyConfigProvider | null = null;\n let proxyOpts: ProxyOpts | null = null;\n if (cliArgs.proxy && config.proxy) {\n proxyProvider = detectProxyProvider(config.proxy.provider);\n proxyOpts = {\n host: cliArgs.proxyHost ?? config.proxy.host ?? platform.defaultTraefikHost,\n domain: env['GUESTHUB_DOMAIN'] ?? env['DOMAIN'] ?? 'localhost',\n routes: config.proxy.routes,\n tls: cliArgs.proxyTls ?? config.proxy.tls ?? true,\n entrypoint: cliArgs.proxyEntrypoint ?? config.proxy.entrypoint ?? 'websecure',\n confPath: cliArgs.proxyConf ?? config.proxy.confPath ?? join(homedir(), '.traefik', 'traefik_conf.yaml'),\n };\n }\n\n // Render TUI\n const isInteractive = process.stdin.isTTY ?? false;\n const { waitUntilExit } = render(\n React.createElement(App, {\n config, services, cliArgs, platform, env, baseCwd: cwd,\n proxyProvider, proxyOpts,\n }),\n { exitOnCtrlC: false, patchConsole: isInteractive, interactive: isInteractive },\n );\n\n await waitUntilExit();\n}\n\nmain().catch(e => {\n console.error(e);\n process.exit(1);\n});\n","import { existsSync } from 'node:fs';\nimport { readFile } from 'node:fs/promises';\nimport { resolve, join } from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport type { DevStackConfig } from './types.js';\n\nconst CONFIG_NAMES = [\n 'devup.config.ts',\n 'devup.config.js',\n 'devup.config.json',\n];\n\nexport function findConfigFile(cwd: string, explicit?: string): string {\n if (explicit) {\n const full = resolve(cwd, explicit);\n if (!existsSync(full)) throw new Error(`Config not found: ${full}`);\n return full;\n }\n for (const name of CONFIG_NAMES) {\n const full = join(cwd, name);\n if (existsSync(full)) return full;\n }\n throw new Error(\n `No config found. Create one of: ${CONFIG_NAMES.join(', ')}\\n` +\n `Or use --config <path>`,\n );\n}\n\nexport async function loadConfig(configPath: string): Promise<DevStackConfig> {\n if (configPath.endsWith('.json')) {\n const raw = await readFile(configPath, 'utf8');\n return JSON.parse(raw) as DevStackConfig;\n }\n\n // .ts and .js — dynamic import (tsx loader handles .ts at runtime)\n const url = pathToFileURL(configPath).href;\n const mod = await import(url);\n const config = mod.default ?? mod;\n\n if (!config || typeof config !== 'object' || !Array.isArray(config.services)) {\n throw new Error(`Invalid config: must export a DevStackConfig (use defineConfig() from @gachlab/devup)`);\n }\n\n return config as DevStackConfig;\n}\n","import { existsSync } from 'node:fs';\nimport { resolve } from 'node:path';\nimport type { DevStackConfig } from './types.js';\n\nexport interface ValidationError {\n field: string;\n message: string;\n}\n\nexport function validateConfig(config: DevStackConfig, cwd: string): ValidationError[] {\n const errors: ValidationError[] = [];\n\n if (!config.name?.trim()) {\n errors.push({ field: 'name', message: 'Project name is required' });\n }\n\n if (!config.services?.length) {\n errors.push({ field: 'services', message: 'At least one service is required' });\n return errors;\n }\n\n // Unique names\n const names = new Set<string>();\n for (const svc of config.services) {\n if (names.has(svc.name)) {\n errors.push({ field: `services[${svc.name}].name`, message: `Duplicate service name: ${svc.name}` });\n }\n names.add(svc.name);\n }\n\n // Unique ports\n const ports = new Map<number, string>();\n for (const svc of config.services) {\n const existing = ports.get(svc.port);\n if (existing) {\n errors.push({ field: `services[${svc.name}].port`, message: `Port ${svc.port} already used by ${existing}` });\n }\n ports.set(svc.port, svc.name);\n }\n\n // Valid fields per service\n for (const svc of config.services) {\n if (!svc.name?.trim()) errors.push({ field: 'services[].name', message: 'Service name is required' });\n if (!svc.cwd?.trim()) errors.push({ field: `services[${svc.name}].cwd`, message: 'cwd is required' });\n if (!svc.cmd?.trim()) errors.push({ field: `services[${svc.name}].cmd`, message: 'cmd is required' });\n if (!svc.type || !['api', 'web'].includes(svc.type)) {\n errors.push({ field: `services[${svc.name}].type`, message: `Invalid type: ${svc.type} (must be \"api\" or \"web\")` });\n }\n if (typeof svc.port !== 'number' || svc.port <= 0) {\n errors.push({ field: `services[${svc.name}].port`, message: `Invalid port: ${svc.port}` });\n }\n if (typeof svc.phase !== 'number' || svc.phase < 0) {\n errors.push({ field: `services[${svc.name}].phase`, message: `Invalid phase: ${svc.phase}` });\n }\n\n // cwd exists\n if (svc.cwd && !existsSync(resolve(cwd, svc.cwd))) {\n errors.push({ field: `services[${svc.name}].cwd`, message: `Directory not found: ${svc.cwd}` });\n }\n }\n\n // Lazy refs\n if (config.lazy?.alwaysOn) {\n for (const ref of config.lazy.alwaysOn) {\n if (!names.has(ref)) {\n errors.push({ field: `lazy.alwaysOn`, message: `Unknown service: ${ref}` });\n }\n }\n }\n\n // Proxy route refs\n if (config.proxy?.routes) {\n for (const ref of Object.keys(config.proxy.routes)) {\n if (!names.has(ref)) {\n errors.push({ field: `proxy.routes`, message: `Unknown service: ${ref}` });\n }\n }\n }\n\n return errors;\n}\n\nexport function formatValidationErrors(errors: ValidationError[]): string {\n return errors.map(e => ` ✗ ${e.field}: ${e.message}`).join('\\n');\n}\n","import type { ServiceConfig } from './types.js';\n\nexport interface CliArgs {\n configPath?: string;\n only?: string;\n skip: string[];\n services?: string[];\n lazy: boolean;\n lazyTimeout: number;\n proxy: boolean;\n proxyHost?: string;\n proxyConf?: string;\n proxyTls: boolean;\n proxyEntrypoint: string;\n}\n\nconst DEFAULT_LAZY_TIMEOUT = 10;\n\nexport function parseCliArgs(argv: string[]): CliArgs {\n const args: CliArgs = {\n skip: [],\n lazy: true,\n lazyTimeout: DEFAULT_LAZY_TIMEOUT,\n proxy: false,\n proxyTls: true,\n proxyEntrypoint: 'websecure',\n };\n\n for (let i = 0; i < argv.length; i++) {\n const arg = argv[i]!;\n const next = argv[i + 1];\n\n switch (arg) {\n case '--config': args.configPath = next; i++; break;\n case '--only': args.only = next; i++; break;\n case '--skip': args.skip = next?.split(',') ?? []; i++; break;\n case '--services': args.services = next?.split(','); i++; break;\n case '--lazy': args.lazy = true; break;\n case '--no-lazy': args.lazy = false; break;\n case '--timeout': args.lazyTimeout = parseInt(next ?? '', 10) || DEFAULT_LAZY_TIMEOUT; i++; break;\n case '--proxy': args.proxy = true; break;\n case '--proxy-host': args.proxyHost = next; i++; break;\n case '--proxy-conf': args.proxyConf = next; i++; break;\n case '--proxy-tls': args.proxyTls = true; break;\n case '--no-proxy-tls': args.proxyTls = false; break;\n case '--proxy-entrypoint': args.proxyEntrypoint = next ?? 'websecure'; i++; break;\n }\n }\n\n return args;\n}\n\nexport function filterServices(services: ServiceConfig[], args: CliArgs): ServiceConfig[] {\n let result = services;\n\n if (args.services) {\n const explicit = new Set(args.services);\n result = result.filter(s => explicit.has(s.name));\n } else if (args.only) {\n switch (args.only) {\n case 'apis': result = result.filter(s => s.type === 'api'); break;\n case 'webs': result = result.filter(s => s.type === 'web'); break;\n default: result = result.filter(s => s.name.startsWith(args.only!)); break;\n }\n }\n\n if (args.skip.length) {\n const skipSet = new Set(args.skip);\n result = result.filter(s => !skipSet.has(s.name));\n }\n\n return result;\n}\n","import type { Platform } from './types.js';\n\nexport async function detectPlatform(): Promise<Platform> {\n switch (process.platform) {\n case 'linux': {\n const { LinuxPlatform } = await import('./linux.js');\n return new LinuxPlatform();\n }\n case 'darwin': {\n const { DarwinPlatform } = await import('./darwin.js');\n return new DarwinPlatform();\n }\n case 'win32': {\n const { Win32Platform } = await import('./win32.js');\n return new Win32Platform();\n }\n default:\n throw new Error(`Unsupported platform: ${process.platform}`);\n }\n}\n","import { existsSync, mkdirSync, writeFileSync } from 'node:fs';\nimport { dirname } from 'node:path';\nimport type { ProxyConfigProvider, ProxyOpts, ServiceState } from './types.js';\n\nconst EMPTY_CONFIG = 'http:\\n routers: {}\\n services: {}\\n';\n\nexport class TraefikProvider implements ProxyConfigProvider {\n readonly name = 'traefik';\n\n generate(services: Map<string, ServiceState>, opts: ProxyOpts): string {\n const routers: string[] = [];\n const svcs: string[] = [];\n\n for (const [name, st] of services) {\n if (st.health !== 'up') continue;\n const sub = opts.routes[name];\n if (sub === undefined) continue;\n\n const rule = sub ? `Host(\\`${sub}.${opts.domain}\\`)` : `Host(\\`${opts.domain}\\`)`;\n const safe = name.replace(/[^a-z0-9-]/g, '-');\n const port = st.realPort ?? st.port;\n\n let router = ` ${safe}:\\n rule: \"${rule}\"\\n service: ${safe}\\n entryPoints:\\n - ${opts.entrypoint}`;\n if (opts.tls) router += `\\n tls:\\n certResolver: le`;\n routers.push(router);\n\n svcs.push(` ${safe}:\\n loadBalancer:\\n servers:\\n - url: \"http://${opts.host}:${port}\"`);\n }\n\n if (!routers.length) return EMPTY_CONFIG;\n return `http:\\n routers:\\n${routers.join('\\n')}\\n services:\\n${svcs.join('\\n')}\\n`;\n }\n\n write(content: string, opts: ProxyOpts): void {\n const dir = dirname(opts.confPath);\n if (!existsSync(dir)) mkdirSync(dir, { recursive: true });\n writeFileSync(opts.confPath, content);\n }\n\n clear(opts: ProxyOpts): void {\n this.write(EMPTY_CONFIG, opts);\n }\n}\n","import type { ProxyConfigProvider } from './types.js';\nimport { TraefikProvider } from './traefik.js';\n\nconst providers: Record<string, () => ProxyConfigProvider> = {\n traefik: () => new TraefikProvider(),\n};\n\nexport function detectProxyProvider(name: string): ProxyConfigProvider {\n const factory = providers[name];\n if (!factory) {\n const available = Object.keys(providers).join(', ');\n throw new Error(`Unknown proxy provider: \"${name}\". Available: ${available}`);\n }\n return factory();\n}\n","import { existsSync, readFileSync, writeFileSync } from 'node:fs';\nimport { createHash } from 'node:crypto';\nimport { join } from 'node:path';\nimport type { ServiceConfig } from './config/types.js';\n\n// ── .env parsing ──\n\nexport function parseEnvFile(filePath: string, baseEnv: Record<string, string> = {}): Record<string, string> {\n const env = { ...baseEnv };\n if (!existsSync(filePath)) return env;\n\n for (const line of readFileSync(filePath, 'utf8').split('\\n')) {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith('#')) continue;\n const eqIdx = trimmed.indexOf('=');\n if (eqIdx === -1) continue;\n const key = trimmed.slice(0, eqIdx).trim();\n let val = trimmed.slice(eqIdx + 1).trim();\n if ((val.startsWith('\"') && val.endsWith('\"')) || (val.startsWith(\"'\") && val.endsWith(\"'\"))) {\n val = val.slice(1, -1);\n }\n if (!env[key]) env[key] = val;\n }\n return env;\n}\n\n// ── Format helpers ──\n\nexport function fmtUptime(ms: number): string {\n if (!ms || ms < 0) return '-';\n const s = Math.floor(ms / 1000);\n if (s < 60) return `${s}s`;\n const m = Math.floor(s / 60);\n if (m < 60) return `${m}m${s % 60}s`;\n const h = Math.floor(m / 60);\n return `${h}h${m % 60}m`;\n}\n\n// ── Search / highlight ──\n\nexport function highlightSearch(text: string, term: string | null, escapeFn?: (s: string) => string): string {\n const escaped = escapeFn ? escapeFn(text) : text;\n if (!term) return escaped;\n const idx = escaped.toLowerCase().indexOf(term.toLowerCase());\n if (idx === -1) return escaped;\n return `${escaped.slice(0, idx)}{black-fg}{yellow-bg}${escaped.slice(idx, idx + term.length)}{/yellow-bg}{/black-fg}${escaped.slice(idx + term.length)}`;\n}\n\nexport function findSearchMatch(\n lines: string[], term: string, currentScroll: number,\n direction: 'next' | 'prev', stripTagsFn?: (s: string) => string,\n): number {\n if (!term || !lines.length) return -1;\n const lower = term.toLowerCase();\n const len = lines.length;\n const start = direction === 'next' ? currentScroll + 1 : currentScroll - 1;\n for (let i = 0; i < len; i++) {\n const idx = direction === 'next' ? (start + i) % len : (start - i + len) % len;\n const raw = stripTagsFn ? stripTagsFn(lines[idx] ?? '') : (lines[idx] ?? '');\n if (raw.toLowerCase().includes(lower)) return idx;\n }\n return -1;\n}\n\n// ── Log formatting ──\n\nexport function formatLogLine(\n svcName: string, line: string, colorTag: string, maxNameLen: number,\n showTimestamps: boolean, searchTerm: string | null, escapeFn?: (s: string) => string,\n): string {\n const padded = svcName.padEnd(maxNameLen);\n const ts = showTimestamps ? `{#666666-fg}[${new Date().toLocaleTimeString('en-GB')}]{/#666666-fg} ` : '';\n const highlighted = highlightSearch(line, searchTerm, escapeFn);\n return `${ts}{${colorTag}-fg}[${padded}]{/${colorTag}-fg} ${highlighted}`;\n}\n\nexport function shouldLogLine(svcName: string, filter: string | null): boolean {\n return !filter || filter === svcName;\n}\n\nexport function buildLogsLabel(filter: string | null, searchTerm: string | null, paused: boolean): string {\n const parts = [' {bold}Logs{/bold}'];\n if (filter) parts.push(`[${filter}]`);\n if (searchTerm) parts.push(`{yellow-fg}/${searchTerm}{/yellow-fg}`);\n if (paused) parts.push('{red-fg}[PAUSED]{/red-fg}');\n return parts.join(' ') + ' ';\n}\n\n// ── npm install stamps ──\n\nexport function needsInstall(fullCwd: string): boolean {\n const nm = join(fullCwd, 'node_modules');\n if (!existsSync(nm)) return true;\n try {\n const pkgHash = createHash('md5').update(readFileSync(join(fullCwd, 'package.json'))).digest('hex');\n const stampFile = join(nm, '.install-stamp');\n if (existsSync(stampFile) && readFileSync(stampFile, 'utf8') === pkgHash) return false;\n } catch { /* stamp missing or unreadable */ }\n return true;\n}\n\nexport function writeInstallStamp(fullCwd: string): void {\n try {\n const pkgHash = createHash('md5').update(readFileSync(join(fullCwd, 'package.json'))).digest('hex');\n writeFileSync(join(fullCwd, 'node_modules', '.install-stamp'), pkgHash);\n } catch { /* best effort */ }\n}\n\n// ── Sort helpers ──\n\nexport function sortServiceNames(\n names: string[], sortMode: string,\n statsMap: Record<string, { cpu?: string; mem?: string }>,\n procState: Record<string, { errors?: number }>,\n): string[] {\n if (sortMode === 'name') return names.slice().sort();\n return names.slice().sort((a, b) => {\n if (sortMode === 'mem') {\n return (parseFloat(statsMap[b]?.mem ?? '0') || 0) - (parseFloat(statsMap[a]?.mem ?? '0') || 0);\n }\n return (procState[b]?.errors ?? 0) - (procState[a]?.errors ?? 0);\n });\n}\n\n// ── Phase grouping ──\n\nexport function groupByPhase(services: ServiceConfig[]): Record<number, ServiceConfig[]> {\n const phases: Record<number, ServiceConfig[]> = {};\n for (const s of services) {\n (phases[s.phase] ??= []).push(s);\n }\n return phases;\n}\n\n// ── Process args / env builders ──\n\nexport function buildProcessArgs(svc: ServiceConfig): string[] {\n const extra = svc.nodeArgs ?? [];\n if (!svc.maxMem) return [...extra, ...svc.args];\n if (svc.cmd === 'node') return [`--max-old-space-size=${svc.maxMem}`, ...extra, ...svc.args];\n return [...extra, ...svc.args];\n}\n\nexport function buildProcessEnv(svc: ServiceConfig, baseEnv: Record<string, string>): Record<string, string> {\n const env = { ...baseEnv, ...(svc.extraEnv ?? {}) };\n if (svc.maxMem && svc.cmd !== 'node') {\n const existing = env['NODE_OPTIONS'] ?? '';\n const flag = `--max-old-space-size=${svc.maxMem}`;\n if (!existing.includes('max-old-space-size')) {\n env['NODE_OPTIONS'] = existing ? `${existing} ${flag}` : flag;\n }\n }\n return env;\n}\n\n// ── CPU percent calculation ──\n\nexport function calcCpuPercent(totalCpuSec: number, prevCpu: number, prevTime: number): number {\n const elapsed = (Date.now() - prevTime) / 1000;\n const cpuDelta = totalCpuSec - prevCpu;\n return elapsed > 0 ? (cpuDelta / elapsed) * 100 : 0;\n}\n\n// ── Color palette ──\n\nexport const tagColors = [\n 'cyan', 'yellow', 'green', 'magenta', 'blue',\n 'red', '#5faf5f', '#d7af5f', '#5f87d7', '#af5faf',\n '#5fd7d7', '#d75f5f', 'white',\n];\n","import React, { useEffect, useState, useCallback, useRef } from 'react';\nimport { Box, Text, useStdout } from 'ink';\nimport type { Platform } from '../platform/types.js';\nimport type { DevStackConfig, ServiceConfig } from '../config/types.js';\nimport type { CliArgs } from '../config/cli.js';\nimport type { ProxyConfigProvider, ProxyOpts } from '../proxy-config/types.js';\nimport { useProcessManager } from './hooks/useProcessManager.js';\nimport { useKeyBindings } from './hooks/useKeyBindings.js';\nimport { useProxySync } from './hooks/useProxySync.js';\nimport { LogsPanel } from './LogsPanel.js';\nimport { StatsPanel } from './StatsPanel.js';\nimport { StatusBar } from './StatusBar.js';\nimport { ServiceList } from './ServiceList.js';\nimport { SearchInput } from './SearchInput.js';\nimport { groupByPhase } from '../utils.js';\nimport { waitForPort } from '../process/health.js';\nimport { classifyServices, rewriteServicePort } from '../lazy/classifier.js';\nimport { createLazyProxy, type LazyProxy } from '../lazy/proxy.js';\nimport type { ProcessState } from '../process/types.js';\n\ninterface Props {\n config: DevStackConfig;\n services: ServiceConfig[];\n cliArgs: CliArgs;\n platform: Platform;\n env: Record<string, string>;\n baseCwd: string;\n proxyProvider: ProxyConfigProvider | null;\n proxyOpts: ProxyOpts | null;\n}\n\nexport function App({ config, services, cliArgs, platform, env, baseCwd, proxyProvider, proxyOpts }: Props) {\n const { stdout } = useStdout();\n const rows = stdout?.rows ?? 40;\n const logsHeight = Math.floor(rows * 0.65);\n const statsHeight = rows - logsHeight - 2; // 2 for header + statusbar\n const maxNameLen = Math.max(...services.map(s => s.name.length), 10);\n\n const pm = useProcessManager(platform, baseCwd, env);\n const [booted, setBooted] = useState(false);\n const lazyProxies = useRef<Map<string, LazyProxy>>(new Map());\n\n const kb = useKeyBindings({\n onQuit: () => {\n lazyProxies.current.forEach(p => p.destroy());\n pm.cleanup();\n process.exit(0);\n },\n onClearLogs: () => {},\n onToggleProxy: () => {},\n });\n\n useProxySync(proxyProvider, proxyOpts, pm.states, kb.proxyEnabled);\n\n // Boot sequence\n useEffect(() => {\n if (booted || !pm.manager) return;\n setBooted(true);\n const mgr = pm.manager;\n\n (async () => {\n const lazyMode = cliArgs.lazy;\n const lazyTimeout = cliArgs.lazyTimeout;\n\n if (lazyMode && config.lazy) {\n // ── Lazy mode ──\n const { alwaysOn, lazy } = classifyServices(services, config.lazy);\n\n // Boot always-on services normally\n const aoPhases = groupByPhase(alwaysOn);\n let colorIdx = 0;\n for (const num of Object.keys(aoPhases).map(Number).sort((a, b) => a - b)) {\n const svcs = aoPhases[num]!;\n for (const svc of svcs) {\n await mgr.install(svc);\n await mgr.start(svc, colorIdx++);\n }\n const apis = svcs.filter(s => s.type === 'api');\n if (apis.length) await Promise.all(apis.map(s => waitForPort(s.port, { timeout: 45000 })));\n svcs.filter(s => s.type === 'web').forEach(s => {\n const st = mgr.state.get(s.name);\n if (st) st.status = 'running';\n });\n }\n\n // Set up lazy proxies\n for (const svc of lazy) {\n const ci = colorIdx++;\n const rewritten = rewriteServicePort(svc);\n\n // Register as idle in process state\n const idleState: ProcessState = {\n svc: rewritten, proc: null, pid: null,\n status: 'idle', health: 'idle',\n errors: 0, restarts: 0, startedAt: null,\n intentionalStop: false, colorIdx: ci,\n };\n mgr.state.set(svc.name, idleState);\n\n const proxy = createLazyProxy({\n listenPort: svc.port,\n targetPort: rewritten.realPort,\n timeoutMin: lazyTimeout,\n onDemandStart: async () => {\n await mgr.install(rewritten);\n await mgr.start(rewritten, ci);\n const ok = await waitForPort(rewritten.realPort, { timeout: 45000 });\n const st = mgr.state.get(svc.name);\n if (st) {\n st.status = ok ? 'running' : 'timeout';\n if (ok) st.health = 'up';\n }\n },\n onIdleStop: () => {\n mgr.stop(svc.name);\n const st = mgr.state.get(svc.name);\n if (st) { st.status = 'idle'; st.health = 'idle'; st.pid = null; st.proc = null; st.startedAt = null; }\n },\n isAlive: () => {\n const st = mgr.state.get(svc.name);\n return !!st && !!st.proc && !st.proc.killed && st.health === 'up';\n },\n });\n\n lazyProxies.current.set(svc.name, proxy);\n }\n } else {\n // ── Normal mode ──\n const phases = groupByPhase(services);\n let colorIdx = 0;\n for (const num of Object.keys(phases).map(Number).sort((a, b) => a - b)) {\n const svcs = phases[num]!;\n for (const svc of svcs) {\n await mgr.install(svc);\n await mgr.start(svc, colorIdx++);\n }\n const apis = svcs.filter(s => s.type === 'api');\n if (apis.length) await Promise.all(apis.map(s => waitForPort(s.port, { timeout: 45000 })));\n svcs.filter(s => s.type === 'web').forEach(s => {\n const st = mgr.state.get(s.name);\n if (st) st.status = 'running';\n });\n }\n }\n })();\n }, [booted, pm.manager, services, cliArgs, config.lazy]);\n\n const handleFilterSelect = useCallback((name: string) => kb.setFilter(name), [kb]);\n const handleRestartSelect = useCallback((name: string) => { pm.restart(name); kb.setModal('none'); }, [pm, kb]);\n const handleOpenSelect = useCallback((name: string) => {\n const st = pm.states.get(name);\n if (st) platform.openBrowser(`http://localhost:${st.svc.port}`);\n kb.setModal('none');\n }, [pm, platform, kb]);\n\n const icon = config.icon ?? '📦';\n const modeLabel = cliArgs.lazy && config.lazy ? 'lazy' : 'normal';\n\n return (\n <Box flexDirection=\"column\" height={rows}>\n <Box><Text bold color=\"cyan\"> {icon} {config.name} — devup — {services.length} services ({modeLabel}) </Text></Box>\n\n <LogsPanel\n logs={pm.logs} filter={kb.logFilter} searchTerm={kb.searchTerm}\n paused={kb.logsPaused} showTimestamps={kb.showTimestamps}\n maxNameLen={maxNameLen} height={logsHeight} focused={kb.panel === 'logs'}\n scrollOffset={kb.logsScrollOffset} resetScroll={kb.resetLogsScroll}\n />\n\n <StatsPanel\n states={pm.states} stats={pm.stats} sortMode={kb.sortMode}\n maxNameLen={maxNameLen} height={statsHeight} focused={kb.panel === 'stats'}\n scrollOffset={kb.statsScrollOffset} resetScroll={kb.resetStatsScroll}\n />\n\n {kb.modal === 'filter' && (\n <ServiceList title=\"Filter by service\" services={pm.states} onSelect={handleFilterSelect} onClose={() => kb.setModal('none')} />\n )}\n {kb.modal === 'restart' && (\n <ServiceList title=\"Restart service\" services={pm.states} onSelect={handleRestartSelect} onClose={() => kb.setModal('none')} />\n )}\n {kb.modal === 'open' && (\n <ServiceList title=\"Open in browser\" services={pm.states} onSelect={handleOpenSelect} onClose={() => kb.setModal('none')} filterType=\"web\" />\n )}\n {kb.modal === 'search' && (\n <SearchInput onSubmit={kb.setSearch} onClose={() => kb.setModal('none')} />\n )}\n\n <StatusBar />\n </Box>\n );\n}\n","import { useState, useEffect, useRef, useCallback } from 'react';\nimport { ProcessManager } from '../../process/manager.js';\nimport type { ProcessState } from '../../process/types.js';\nimport type { Platform } from '../../platform/types.js';\nimport type { ServiceConfig } from '../../config/types.js';\nimport { calcCpuPercent, tagColors } from '../../utils.js';\n\nexport interface LogEntry {\n svcName: string;\n text: string;\n colorIdx: number;\n ts: number;\n}\n\nexport interface ServiceStats {\n cpu: string;\n mem: string;\n}\n\nexport function useProcessManager(platform: Platform, baseCwd: string, env: Record<string, string>) {\n const [states, setStates] = useState<Map<string, ProcessState>>(new Map());\n const [logs, setLogs] = useState<LogEntry[]>([]);\n const [stats, setStats] = useState<Map<string, ServiceStats>>(new Map());\n const mgrRef = useRef<ProcessManager | null>(null);\n const prevCpu = useRef<Map<string, { time: number; cpu: number }>>(new Map());\n\n useEffect(() => {\n const mgr = new ProcessManager({\n baseCwd, env, platform,\n events: {\n onLog: (svcName, text, colorIdx) => {\n const lines = text.split('\\n').filter(Boolean);\n setLogs(prev => {\n const next = [...prev, ...lines.map(l => ({ svcName, text: l, colorIdx, ts: Date.now() }))];\n return next.length > 5000 ? next.slice(-5000) : next;\n });\n },\n onStateChange: () => setStates(new Map(mgr.state)),\n },\n });\n mgrRef.current = mgr;\n return () => { mgr.cleanup(); };\n }, [baseCwd, env, platform]);\n\n // Health + stats polling\n useEffect(() => {\n const id = setInterval(async () => {\n const mgr = mgrRef.current;\n if (!mgr) return;\n await mgr.checkAllHealth();\n setStates(new Map(mgr.state));\n\n const pids: number[] = [];\n const pidMap = new Map<number, string>();\n for (const [name, st] of mgr.state) {\n if (st.pid) { pids.push(st.pid); pidMap.set(st.pid, name); }\n }\n if (pids.length) {\n const raw = await platform.getProcessStats(pids);\n const next = new Map<string, ServiceStats>();\n for (const [pid, data] of raw) {\n const name = pidMap.get(pid);\n if (!name) continue;\n const prev = prevCpu.current.get(name) ?? { time: Date.now(), cpu: 0 };\n const cpuPct = calcCpuPercent(data.cpuSeconds, prev.cpu, prev.time);\n prevCpu.current.set(name, { time: Date.now(), cpu: data.cpuSeconds });\n next.set(name, { cpu: cpuPct.toFixed(1) + '%', mem: (data.rss / 1024).toFixed(1) + ' MB' });\n }\n setStats(next);\n }\n }, 3000);\n return () => clearInterval(id);\n }, [platform]);\n\n const mgr = mgrRef.current;\n\n return {\n states, logs, stats,\n start: useCallback((svc: ServiceConfig, colorIdx: number) => mgr?.start(svc, colorIdx), [mgr]),\n stop: useCallback((name: string) => mgr?.stop(name), [mgr]),\n restart: useCallback((name: string) => mgr?.restart(name), [mgr]),\n install: useCallback((svc: ServiceConfig) => mgr?.install(svc), [mgr]),\n cleanup: useCallback(() => mgr?.cleanup(), [mgr]),\n manager: mgr,\n };\n}\n","import { spawn } from 'node:child_process';\nimport { join } from 'node:path';\nimport type { ChildProcess } from 'node:child_process';\nimport type { Platform } from '../platform/types.js';\nimport type { ServiceConfig } from '../config/types.js';\nimport type { ProcessState, ProcessManagerEvents } from './types.js';\nimport { checkPort, deriveHealth } from './health.js';\nimport { installService } from './installer.js';\nimport { buildProcessArgs, buildProcessEnv } from '../utils.js';\n\nconst MAX_RESTARTS = 3;\nconst BACKOFF_BASE_MS = 2000;\n\nexport class ProcessManager {\n readonly state = new Map<string, ProcessState>();\n private readonly procs = new Set<ChildProcess>();\n private readonly baseCwd: string;\n private readonly env: Record<string, string>;\n private readonly platform: Platform;\n private readonly events: ProcessManagerEvents;\n\n constructor(opts: {\n baseCwd: string;\n env: Record<string, string>;\n platform: Platform;\n events: ProcessManagerEvents;\n }) {\n this.baseCwd = opts.baseCwd;\n this.env = opts.env;\n this.platform = opts.platform;\n this.events = opts.events;\n }\n\n async install(svc: ServiceConfig): Promise<boolean> {\n const cwd = join(this.baseCwd, svc.cwd);\n return installService(cwd, this.env, msg => this.log(svc.name, msg, this.getColorIdx(svc.name)));\n }\n\n async start(svc: ServiceConfig, colorIdx: number, isRestart = false): Promise<void> {\n const cwd = join(this.baseCwd, svc.cwd);\n\n // Port occupied check\n if (svc.type === 'api') {\n const occupied = await checkPort(svc.port);\n if (occupied && !isRestart) {\n this.log(svc.name, `⚠ port ${svc.port} already in use — skipping`, colorIdx);\n return;\n }\n }\n\n const args = buildProcessArgs(svc);\n const env = buildProcessEnv(svc, this.env);\n const proc = spawn(svc.cmd, args, { cwd, env, detached: true, stdio: ['ignore', 'pipe', 'pipe'] });\n\n const prev = this.state.get(svc.name);\n const state: ProcessState = {\n svc, proc, pid: proc.pid ?? null,\n status: 'starting', health: 'wait',\n errors: prev?.errors ?? 0,\n restarts: prev?.restarts ?? 0,\n startedAt: Date.now(),\n intentionalStop: false,\n colorIdx,\n };\n this.state.set(svc.name, state);\n this.procs.add(proc);\n this.events.onStateChange(svc.name, state);\n\n proc.stdout?.on('data', (d: Buffer) => this.log(svc.name, d.toString(), colorIdx));\n proc.stderr?.on('data', (d: Buffer) => {\n state.errors += d.toString().split('\\n').filter(Boolean).length;\n this.log(svc.name, d.toString(), colorIdx);\n });\n\n proc.on('close', code => {\n this.procs.delete(proc);\n if (state.intentionalStop) { state.intentionalStop = false; return; }\n if (code === 0) {\n state.status = 'stopped'; state.health = 'down';\n this.events.onStateChange(svc.name, state);\n return;\n }\n state.status = 'crashed'; state.health = 'down';\n this.log(svc.name, `❌ exited with code ${code}`, colorIdx);\n this.events.onStateChange(svc.name, state);\n\n if (state.restarts < MAX_RESTARTS) {\n state.restarts++;\n const delay = BACKOFF_BASE_MS * Math.pow(2, state.restarts - 1);\n this.log(svc.name, `🔄 auto-restart ${state.restarts}/${MAX_RESTARTS} in ${delay}ms...`, colorIdx);\n setTimeout(() => this.start(svc, colorIdx, true), delay);\n } else {\n this.log(svc.name, '⛔ max restarts reached', colorIdx);\n }\n });\n\n this.log(svc.name, isRestart ? `🔄 restarted (:${svc.port})` : `🚀 started (:${svc.port})`, colorIdx);\n }\n\n stop(name: string): void {\n const st = this.state.get(name);\n if (!st?.proc || !st.pid) return;\n st.intentionalStop = true;\n this.platform.killTree(st.pid);\n }\n\n async restart(name: string): Promise<void> {\n const st = this.state.get(name);\n if (!st) return;\n this.stop(name);\n st.restarts++;\n const delay = st.proc ? 1500 : 100;\n await new Promise(r => setTimeout(r, delay));\n await this.start(st.svc, st.colorIdx, true);\n this.log(name, '🔄 manual restart', st.colorIdx);\n }\n\n async checkAllHealth(): Promise<void> {\n for (const [name, st] of this.state) {\n if (!st.pid || st.status === 'idle') {\n st.health = st.status === 'idle' ? 'idle' : 'down';\n continue;\n }\n const port = st.svc.port;\n const isUp = await checkPort(port);\n const prev = st.health;\n st.health = deriveHealth(isUp, st.status);\n if (st.health === 'up' && st.status === 'starting') st.status = 'running';\n if (prev !== st.health) this.events.onStateChange(name, st);\n }\n }\n\n cleanup(): void {\n for (const proc of this.procs) {\n if (proc.pid) this.platform.killTree(proc.pid);\n }\n // Force kill after 3s\n setTimeout(() => {\n for (const proc of this.procs) {\n if (proc.pid) this.platform.killTree(proc.pid, 'SIGKILL');\n }\n }, 3000);\n }\n\n private log(name: string, text: string, colorIdx: number): void {\n this.events.onLog(name, text, colorIdx);\n }\n\n private getColorIdx(name: string): number {\n return this.state.get(name)?.colorIdx ?? 0;\n }\n}\n","import net from 'node:net';\nimport type { HealthStatus } from './types.js';\n\nexport function checkPort(port: number, host = '127.0.0.1'): Promise<boolean> {\n return new Promise(resolve => {\n const socket = new net.Socket();\n socket.setTimeout(2000);\n socket.once('connect', () => { socket.destroy(); resolve(true); });\n socket.once('error', () => { socket.destroy(); resolve(false); });\n socket.once('timeout', () => { socket.destroy(); resolve(false); });\n socket.connect(port, host);\n });\n}\n\nexport function waitForPort(port: number, opts: { timeout?: number; interval?: number } = {}): Promise<boolean> {\n const { timeout = 45000, interval = 1000 } = opts;\n return new Promise(resolve => {\n const start = Date.now();\n const check = () => {\n checkPort(port).then(ok => {\n if (ok) return resolve(true);\n if (Date.now() - start > timeout) return resolve(false);\n setTimeout(check, interval);\n });\n };\n check();\n });\n}\n\nexport function deriveHealth(isUp: boolean, currentStatus: string): HealthStatus {\n if (currentStatus === 'idle') return 'idle';\n if (isUp) return 'up';\n return currentStatus === 'starting' ? 'wait' : 'down';\n}\n","import { spawn } from 'node:child_process';\nimport { existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { needsInstall, writeInstallStamp } from '../utils.js';\n\nexport interface InstallResult {\n name: string;\n ok: boolean;\n error?: string;\n}\n\nexport function installService(\n cwd: string, env: Record<string, string>,\n onLog?: (msg: string) => void,\n): Promise<boolean> {\n if (!existsSync(cwd)) {\n onLog?.(`⚠ directory not found: ${cwd}`);\n return Promise.resolve(false);\n }\n if (!needsInstall(cwd)) {\n onLog?.('✅ dependencies up to date');\n return Promise.resolve(true);\n }\n onLog?.('📦 npm install...');\n return new Promise(resolve => {\n // En Windows, npm es usualmente npm.cmd\n const command = process.platform === 'win32' ? 'npm.cmd' : 'npm';\n const proc = spawn(command, ['install'], { cwd, env, stdio: ['ignore', 'ignore', 'pipe'] });\n let stderr = '';\n proc.stderr?.on('data', (d: Buffer) => { stderr += d.toString(); });\n proc.on('close', code => {\n if (code !== 0) {\n onLog?.(`⚠ npm install failed: ${stderr.split('\\n')[0]}`);\n resolve(false);\n } else {\n writeInstallStamp(cwd);\n onLog?.('✅ dependencies ready');\n resolve(true);\n }\n });\n proc.on('error', (err) => {\n // Si falla con npm.cmd, intentar con npm (o viceversa dependiendo de la plataforma)\n onLog?.(`⚠ spawn error: ${err.message}`);\n resolve(false);\n });\n });\n}\n\nexport async function installBatch(\n items: Array<{ name: string; cwd: string; env: Record<string, string> }>,\n concurrency: number,\n onLog?: (name: string, msg: string) => void,\n): Promise<InstallResult[]> {\n const results: InstallResult[] = [];\n const queue = [...items];\n const running: Promise<void>[] = [];\n\n while (queue.length > 0 || running.length > 0) {\n while (running.length < concurrency && queue.length > 0) {\n const item = queue.shift()!;\n const p = installService(item.cwd, item.env, msg => onLog?.(item.name, msg))\n .then(ok => {\n results.push({ name: item.name, ok });\n running.splice(running.indexOf(p), 1);\n });\n running.push(p);\n }\n if (running.length > 0) await Promise.race(running);\n }\n return results;\n}\n","import { useInput } from 'ink';\nimport { useState, useCallback } from 'react';\n\nexport type Modal = 'none' | 'filter' | 'restart' | 'open' | 'search';\nexport type Panel = 'logs' | 'stats';\n\nexport interface KeyState {\n panel: Panel;\n modal: Modal;\n logFilter: string | null;\n searchTerm: string | null;\n logsPaused: boolean;\n showTimestamps: boolean;\n sortIdx: number;\n proxyEnabled: boolean;\n logsScrollOffset: number;\n statsScrollOffset: number;\n}\n\nconst SORT_MODES = ['name', 'mem', 'errors'] as const;\n\nexport function useKeyBindings(opts: {\n onQuit: () => void;\n onClearLogs: () => void;\n onToggleProxy: () => void;\n}) {\n const [state, setState] = useState<KeyState>({\n panel: 'logs', modal: 'none', logFilter: null, searchTerm: null,\n logsPaused: false, showTimestamps: false, sortIdx: 0, proxyEnabled: false,\n logsScrollOffset: 0, statsScrollOffset: 0,\n });\n\n const setModal = useCallback((modal: Modal) => setState(s => ({ ...s, modal })), []);\n const setFilter = useCallback((f: string | null) => setState(s => ({ ...s, logFilter: f, modal: 'none' })), []);\n const setSearch = useCallback((t: string | null) => setState(s => ({ ...s, searchTerm: t, modal: 'none' })), []);\n\n const isActive = process.stdin.isTTY ?? false;\n\n useInput((input, key) => {\n if (state.modal !== 'none') return;\n\n if (input === 'q' || (key.ctrl && input === 'c')) opts.onQuit();\n else if (input === 'c') opts.onClearLogs();\n else if (key.tab) setState(s => ({ ...s, panel: s.panel === 'logs' ? 'stats' : 'logs' }));\n else if (input === 'f') setModal('filter');\n else if (input === 'r') setModal('restart');\n else if (input === 'o') setModal('open');\n else if (input === '/') setModal('search');\n else if (input === 'a') setState(s => ({ ...s, logFilter: null, searchTerm: null }));\n else if (input === 'p') setState(s => ({ ...s, logsPaused: !s.logsPaused }));\n else if (input === 't') setState(s => ({ ...s, showTimestamps: !s.showTimestamps }));\n else if (input === 's') setState(s => ({ ...s, sortIdx: (s.sortIdx + 1) % SORT_MODES.length }));\n else if (input === 'T') { opts.onToggleProxy(); setState(s => ({ ...s, proxyEnabled: !s.proxyEnabled })); }\n // Navegación con flechas\n else if (key.upArrow) {\n setState(s => {\n if (s.panel === 'logs') {\n return { ...s, logsScrollOffset: Math.max(0, s.logsScrollOffset - 1) };\n } else if (s.panel === 'stats') {\n return { ...s, statsScrollOffset: Math.max(0, s.statsScrollOffset - 1) };\n }\n return s;\n });\n }\n else if (key.downArrow) {\n setState(s => {\n if (s.panel === 'logs') {\n return { ...s, logsScrollOffset: s.logsScrollOffset + 1 };\n } else if (s.panel === 'stats') {\n return { ...s, statsScrollOffset: s.statsScrollOffset + 1 };\n }\n return s;\n });\n }\n // Teclas de página (Page Up/Page Down)\n else if (input === '[' || (key.ctrl && input === 'b')) { // Page Up\n setState(s => {\n if (s.panel === 'logs') {\n return { ...s, logsScrollOffset: Math.max(0, s.logsScrollOffset - 10) };\n } else if (s.panel === 'stats') {\n return { ...s, statsScrollOffset: Math.max(0, s.statsScrollOffset - 10) };\n }\n return s;\n });\n }\n else if (input === ']' || (key.ctrl && input === 'f')) { // Page Down\n setState(s => {\n if (s.panel === 'logs') {\n return { ...s, logsScrollOffset: s.logsScrollOffset + 10 };\n } else if (s.panel === 'stats') {\n return { ...s, statsScrollOffset: s.statsScrollOffset + 10 };\n }\n return s;\n });\n }\n // Ir al inicio/fin\n else if (key.ctrl && input === 'a') { // Home\n setState(s => {\n if (s.panel === 'logs') {\n return { ...s, logsScrollOffset: 0 };\n } else if (s.panel === 'stats') {\n return { ...s, statsScrollOffset: 0 };\n }\n return s;\n });\n }\n else if (key.ctrl && input === 'e') { // End\n setState(s => {\n if (s.panel === 'logs') {\n return { ...s, logsScrollOffset: Number.MAX_SAFE_INTEGER };\n } else if (s.panel === 'stats') {\n return { ...s, statsScrollOffset: Number.MAX_SAFE_INTEGER };\n }\n return s;\n });\n }\n }, { isActive });\n\n return { \n ...state, \n setModal, \n setFilter, \n setSearch, \n sortMode: SORT_MODES[state.sortIdx]!,\n // Funciones para resetear el scroll cuando cambia el contenido\n resetLogsScroll: useCallback(() => setState(s => ({ ...s, logsScrollOffset: 0 })), []),\n resetStatsScroll: useCallback(() => setState(s => ({ ...s, statsScrollOffset: 0 })), []),\n };\n}\n","import { useEffect, useRef } from 'react';\nimport type { ProxyConfigProvider, ProxyOpts, ServiceState } from '../../proxy-config/types.js';\nimport type { ProcessState } from '../../process/types.js';\n\nexport function useProxySync(\n provider: ProxyConfigProvider | null,\n opts: ProxyOpts | null,\n states: Map<string, ProcessState>,\n enabled: boolean,\n) {\n const intervalRef = useRef<ReturnType<typeof setInterval> | null>(null);\n\n useEffect(() => {\n if (!provider || !opts || !enabled) {\n if (intervalRef.current) clearInterval(intervalRef.current);\n return;\n }\n\n const sync = () => {\n const svcStates = new Map<string, ServiceState>();\n for (const [name, st] of states) {\n svcStates.set(name, { port: st.svc.port, health: st.health, realPort: (st.svc as any).realPort });\n }\n const content = provider.generate(svcStates, opts);\n provider.write(content, opts);\n };\n\n sync();\n intervalRef.current = setInterval(sync, 3000);\n return () => { if (intervalRef.current) clearInterval(intervalRef.current); };\n }, [provider, opts, enabled, states]);\n}\n","import React, { useEffect } from 'react';\nimport { Box, Text } from 'ink';\nimport type { LogEntry } from './hooks/useProcessManager.js';\nimport { tagColors } from '../utils.js';\n\ninterface Props {\n logs: LogEntry[];\n filter: string | null;\n searchTerm: string | null;\n paused: boolean;\n showTimestamps: boolean;\n maxNameLen: number;\n height: number;\n focused: boolean;\n scrollOffset: number;\n resetScroll: () => void;\n}\n\nexport function LogsPanel({ logs, filter, searchTerm, paused, showTimestamps, maxNameLen, height, focused, scrollOffset, resetScroll }: Props) {\n const filtered = filter ? logs.filter(l => l.svcName === filter) : logs;\n const contentHeight = height - 2;\n \n // Calcular el índice de inicio basado en el scroll offset\n const totalLines = filtered.length;\n let startIndex = 0;\n \n if (scrollOffset === Number.MAX_SAFE_INTEGER) {\n // Ir al final\n startIndex = Math.max(0, totalLines - contentHeight);\n } else if (scrollOffset > 0) {\n // Desplazamiento manual\n startIndex = Math.min(scrollOffset, Math.max(0, totalLines - contentHeight));\n } else {\n // Comportamiento original: mostrar las últimas líneas\n startIndex = Math.max(0, totalLines - contentHeight);\n }\n \n const visible = filtered.slice(startIndex, startIndex + contentHeight);\n \n // Resetear el scroll cuando cambia el filtro o búsqueda\n useEffect(() => {\n resetScroll();\n }, [filter, searchTerm, resetScroll]);\n\n const label = [\n 'Logs',\n filter ? `[${filter}]` : '',\n searchTerm ? `/${searchTerm}` : '',\n paused ? '[PAUSED]' : '',\n `${filtered.length} lines`,\n focused ? `(${startIndex + 1}-${Math.min(startIndex + contentHeight, totalLines)}/${totalLines})` : '',\n ].filter(Boolean).join(' ');\n\n return (\n <Box flexDirection=\"column\" borderStyle=\"round\" borderColor={focused ? 'cyan' : 'gray'} height={height}>\n <Box><Text bold color=\"cyan\"> {label} </Text></Box>\n {visible.map((entry, i) => {\n const color = tagColors[entry.colorIdx % tagColors.length]!;\n const ts = showTimestamps ? new Date(entry.ts).toLocaleTimeString('en-GB') + ' ' : '';\n const line = entry.text;\n const isMatch = searchTerm && line.toLowerCase().includes(searchTerm.toLowerCase());\n return (\n <Box key={i}>\n {showTimestamps && <Text dimColor>{ts}</Text>}\n <Text color={color}>[{entry.svcName.padEnd(maxNameLen)}]</Text>\n <Text> </Text>\n {isMatch ? <Text backgroundColor=\"yellow\" color=\"black\">{line}</Text> : <Text>{line}</Text>}\n </Box>\n );\n })}\n </Box>\n );\n}\n","import React, { useEffect } from 'react';\nimport { Box, Text } from 'ink';\nimport type { ProcessState } from '../process/types.js';\nimport type { ServiceStats } from './hooks/useProcessManager.js';\nimport { fmtUptime, sortServiceNames, tagColors } from '../utils.js';\nimport os from 'node:os';\n\ninterface Props {\n states: Map<string, ProcessState>;\n stats: Map<string, ServiceStats>;\n sortMode: string;\n maxNameLen: number;\n height: number;\n focused: boolean;\n scrollOffset: number;\n resetScroll: () => void;\n}\n\nconst H: Record<string, { c: string; color: string }> = {\n up: { c: '●', color: 'green' }, wait: { c: '●', color: 'yellow' },\n down: { c: '●', color: 'red' }, idle: { c: '○', color: 'blue' },\n};\n\nfunction Row({ name, st, stat, ml }: { name: string; st: ProcessState; stat?: ServiceStats; ml: number }) {\n const h = H[st.health] ?? H['down']!;\n const color = tagColors[st.colorIdx % tagColors.length]!;\n const sc = st.status === 'running' ? 'green' : st.status === 'starting' ? 'yellow' : st.status === 'idle' ? 'blue' : 'red';\n const up = st.startedAt ? fmtUptime(Date.now() - st.startedAt) : '-';\n return (\n <Text>\n <Text color={h.color}>{h.c}</Text> <Text color={color}>{name.padEnd(ml)}</Text> {String(st.svc.port).padStart(5)} <Text color={sc}>{st.status.padEnd(8)}</Text> {(stat?.cpu ?? '-').padStart(6)} {(stat?.mem ?? '-').padStart(8)} {String(st.errors).padStart(3)} {String(st.restarts).padStart(3)} {up.padStart(6)}\n </Text>\n );\n}\n\nfunction ColHeader({ ml }: { ml: number }) {\n return <Text bold>H {'Service'.padEnd(ml)} {'Port'.padStart(5)} {'Status'.padEnd(8)} {'CPU'.padStart(6)} {'Mem'.padStart(8)} Err Rst {'Up'.padStart(6)}</Text>;\n}\n\nexport function StatsPanel({ states, stats, sortMode, maxNameLen, height, focused, scrollOffset, resetScroll }: Props) {\n const names = [...states.keys()];\n const stObj = Object.fromEntries([...states].map(([k, v]) => [k, { errors: v.errors }]));\n const statsObj = Object.fromEntries([...stats].map(([k, v]) => [k, v]));\n\n const apis = sortServiceNames(names.filter(n => states.get(n)!.svc.type === 'api'), sortMode, statsObj, stObj);\n const webs = sortServiceNames(names.filter(n => states.get(n)!.svc.type === 'web'), sortMode, statsObj, stObj);\n\n // System stats\n const cpus = os.cpus().length;\n const totalGB = (os.totalmem() / 1024 / 1024 / 1024).toFixed(1);\n const usedGB = (parseFloat(totalGB) - os.freemem() / 1024 / 1024 / 1024).toFixed(1);\n const load = os.loadavg()[0]!.toFixed(2);\n\n // Stack totals\n let totalCpu = 0, totalMemMB = 0, totalErrors = 0, totalRestarts = 0;\n for (const name of names) {\n const s = stats.get(name);\n if (s) {\n const c = parseFloat(s.cpu); if (!isNaN(c)) totalCpu += c;\n const m = parseFloat(s.mem); if (!isNaN(m)) totalMemMB += m;\n }\n totalErrors += states.get(name)?.errors ?? 0;\n totalRestarts += states.get(name)?.restarts ?? 0;\n }\n const stackMem = totalMemMB >= 1024 ? (totalMemMB / 1024).toFixed(2) + ' GB' : totalMemMB.toFixed(1) + ' MB';\n\n const ml = maxNameLen;\n const contentHeight = height - 2;\n \n // Calcular el índice de inicio basado en el scroll offset para cada columna\n const maxApiRows = Math.max(0, apis.length - (contentHeight - 2));\n const maxWebRows = Math.max(0, webs.length - (contentHeight - 2));\n \n let apiStartIndex = 0;\n let webStartIndex = 0;\n \n if (scrollOffset === Number.MAX_SAFE_INTEGER) {\n // Ir al final\n apiStartIndex = maxApiRows;\n webStartIndex = maxWebRows;\n } else if (scrollOffset > 0) {\n // Desplazamiento manual\n apiStartIndex = Math.min(scrollOffset, maxApiRows);\n webStartIndex = Math.min(scrollOffset, maxWebRows);\n }\n \n const visibleApis = apis.slice(apiStartIndex, apiStartIndex + contentHeight - 2);\n const visibleWebs = webs.slice(webStartIndex, webStartIndex + contentHeight - 2);\n \n // Resetear el scroll cuando cambia el modo de ordenamiento\n useEffect(() => {\n resetScroll();\n }, [sortMode, resetScroll]);\n\n const totalServices = apis.length + webs.length;\n const positionInfo = focused ? `(${Math.max(apiStartIndex, webStartIndex) + 1}-${Math.max(apiStartIndex, webStartIndex) + contentHeight - 2}/${totalServices})` : '';\n\n return (\n <Box flexDirection=\"column\" borderStyle=\"round\" borderColor={focused ? 'green' : 'gray'} height={height}>\n <Box>\n <Text bold color=\"green\"> Stats {positionInfo}</Text>\n <Text dimColor>System: {cpus}c Load {load} RAM {usedGB}/{totalGB}GB</Text>\n <Text dimColor> │ </Text>\n <Text dimColor>Stack: CPU {totalCpu.toFixed(1)}% RAM {stackMem} Err {totalErrors} Rst {totalRestarts} Svcs {names.length}</Text>\n {sortMode !== 'name' && <Text dimColor> │ Sort: {sortMode}</Text>}\n </Box>\n <Box flexGrow={1}>\n {/* Left column: APIs */}\n <Box flexDirection=\"column\" flexGrow={1} flexBasis={0}>\n <Text bold color=\"cyan\"> APIs ({apis.length})</Text>\n <ColHeader ml={ml} />\n {visibleApis.map(n => (\n <Row key={n} name={n} st={states.get(n)!} stat={stats.get(n)} ml={ml} />\n ))}\n </Box>\n {/* Separator */}\n <Box flexDirection=\"column\" width={1}>\n {Array.from({ length: contentHeight }, (_, i) => <Text key={i} dimColor>│</Text>)}\n </Box>\n {/* Right column: Webs */}\n <Box flexDirection=\"column\" flexGrow={1} flexBasis={0}>\n <Text bold color=\"magenta\"> Webs ({webs.length})</Text>\n <ColHeader ml={ml} />\n {visibleWebs.map(n => (\n <Row key={n} name={n} st={states.get(n)!} stat={stats.get(n)} ml={ml} />\n ))}\n </Box>\n </Box>\n </Box>\n );\n}\n","import React from 'react';\nimport { Box, Text } from 'ink';\n\nexport function StatusBar() {\n return (\n <Box>\n <Text>\n <Text bold>q</Text> Quit <Text bold>Tab</Text> Switch <Text bold>↑↓</Text> Scroll <Text bold>PgUp/PgDn</Text> Page <Text bold>Ctrl+A/E</Text> Home/End <Text bold>c</Text> Clear <Text bold>f</Text> Filter <Text bold>a</Text> All <Text bold>r</Text> Restart <Text bold>/</Text> Search <Text bold>s</Text> Sort <Text bold>o</Text> Open <Text bold>p</Text> Pause <Text bold>t</Text> Time <Text bold>T</Text> Proxy\n </Text>\n </Box>\n );\n}\n","import React, { useState } from 'react';\nimport { Box, Text, useInput } from 'ink';\nimport type { ProcessState } from '../process/types.js';\n\ninterface Props {\n title: string;\n services: Map<string, ProcessState>;\n onSelect: (name: string) => void;\n onClose: () => void;\n filterType?: 'api' | 'web';\n}\n\nexport function ServiceList({ title, services, onSelect, onClose, filterType }: Props) {\n const names = [...services.keys()].filter(n => !filterType || services.get(n)!.svc.type === filterType);\n const [idx, setIdx] = useState(0);\n\n useInput((input, key) => {\n if (key.escape) onClose();\n else if (key.return) { if (names[idx]) onSelect(names[idx]!); }\n else if (key.upArrow) setIdx(i => Math.max(0, i - 1));\n else if (key.downArrow) setIdx(i => Math.min(names.length - 1, i + 1));\n }, { isActive: process.stdin.isTTY ?? false });\n\n return (\n <Box flexDirection=\"column\" borderStyle=\"round\" borderColor=\"cyan\" paddingX={1}>\n <Text bold color=\"cyan\"> {title} </Text>\n {names.map((name, i) => (\n <Box key={name}>\n <Text color={i === idx ? 'cyan' : undefined} inverse={i === idx}> {name} :{services.get(name)!.svc.port} </Text>\n </Box>\n ))}\n <Text dimColor>↑↓ navigate Enter select Esc close</Text>\n </Box>\n );\n}\n","import React, { useState } from 'react';\nimport { Box, Text, useInput } from 'ink';\n\ninterface Props {\n onSubmit: (term: string | null) => void;\n onClose: () => void;\n}\n\nexport function SearchInput({ onSubmit, onClose }: Props) {\n const [value, setValue] = useState('');\n\n useInput((input, key) => {\n if (key.escape) onClose();\n else if (key.return) onSubmit(value.trim() || null);\n else if (key.backspace || key.delete) setValue(v => v.slice(0, -1));\n else if (input && !key.ctrl && !key.meta) setValue(v => v + input);\n }, { isActive: process.stdin.isTTY ?? false });\n\n return (\n <Box borderStyle=\"round\" borderColor=\"yellow\" paddingX={1}>\n <Text bold color=\"yellow\">Search: </Text>\n <Text>{value}</Text>\n <Text dimColor>█</Text>\n </Box>\n );\n}\n","import type { ServiceConfig, LazyConfig } from '../config/types.js';\n\nexport const LAZY_PORT_OFFSET = 10000;\nexport const DEFAULT_LAZY_TIMEOUT = 10;\n\nexport interface ClassifiedServices {\n alwaysOn: ServiceConfig[];\n lazy: ServiceConfig[];\n}\n\nexport function classifyServices(services: ServiceConfig[], config?: LazyConfig): ClassifiedServices {\n const alwaysOnSet = new Set(config?.alwaysOn ?? []);\n const alwaysOn: ServiceConfig[] = [];\n const lazy: ServiceConfig[] = [];\n\n for (const svc of services) {\n if (alwaysOnSet.has(svc.name)) alwaysOn.push(svc);\n else lazy.push(svc);\n }\n return { alwaysOn, lazy };\n}\n\nexport function getLazyRealPort(originalPort: number): number {\n return originalPort + LAZY_PORT_OFFSET;\n}\n\nexport function rewriteServicePort(svc: ServiceConfig): ServiceConfig & { realPort: number; originalPort: number } {\n const realPort = getLazyRealPort(svc.port);\n const args = svc.args.map(a => a === String(svc.port) ? String(realPort) : a);\n const extraEnv = { ...svc.extraEnv, PORT_OVERRIDE: String(realPort) };\n return { ...svc, port: realPort, args, extraEnv, realPort, originalPort: svc.port };\n}\n","import net from 'node:net';\nimport { waitForPort } from '../process/health.js';\n\nexport interface LazyProxyOpts {\n listenPort: number;\n targetPort: number;\n timeoutMin: number;\n onDemandStart: () => Promise<void>;\n onIdleStop: () => void;\n isAlive: () => boolean;\n onLog?: (msg: string) => void;\n}\n\nexport interface LazyProxy {\n server: net.Server;\n resetTimer: () => void;\n destroy: () => void;\n}\n\nexport function createLazyProxy(opts: LazyProxyOpts): LazyProxy {\n const { listenPort, targetPort, timeoutMin, onDemandStart, onIdleStop, isAlive, onLog } = opts;\n let idleTimer: ReturnType<typeof setTimeout> | null = null;\n let starting = false;\n let serviceReady = false;\n let pendingConns: net.Socket[] = [];\n\n function resetTimer() {\n if (idleTimer) clearTimeout(idleTimer);\n if (timeoutMin > 0) {\n idleTimer = setTimeout(() => {\n serviceReady = false;\n onLog?.(`💤 idle ${timeoutMin}min — stopping`);\n onIdleStop();\n }, timeoutMin * 60_000);\n }\n }\n\n function pipeToTarget(client: net.Socket) {\n const target = net.createConnection({ port: targetPort, host: '127.0.0.1', allowHalfOpen: true });\n target.on('error', () => { client.destroy(); });\n client.on('error', () => { target.destroy(); });\n target.on('connect', () => {\n target.on('data', (chunk) => { if (!client.destroyed) client.write(chunk); });\n client.on('data', (chunk) => { if (!target.destroyed) target.write(chunk); });\n target.on('end', () => { if (!client.destroyed) client.end(); });\n client.on('end', () => { if (!target.destroyed) target.end(); });\n });\n }\n\n async function handleConnection(client: net.Socket) {\n resetTimer();\n client.on('error', () => {}); // Prevent uncaught ECONNRESET\n\n if (serviceReady && isAlive()) {\n pipeToTarget(client);\n return;\n }\n\n pendingConns.push(client);\n client.on('close', () => { pendingConns = pendingConns.filter(s => s !== client); });\n\n if (starting) return;\n starting = true;\n\n onLog?.('⚡ on-demand start');\n try {\n await onDemandStart();\n const ok = await waitForPort(targetPort, { timeout: 45000, interval: 500 });\n if (ok) serviceReady = true;\n else onLog?.('⚠ timeout waiting for service');\n } catch (e: unknown) {\n onLog?.(`❌ start failed: ${(e as Error).message}`);\n }\n starting = false;\n\n const conns = pendingConns.splice(0);\n for (const conn of conns) {\n if (!conn.destroyed) pipeToTarget(conn);\n }\n }\n\n const server = net.createServer({ allowHalfOpen: true }, socket => handleConnection(socket));\n server.listen(listenPort, '0.0.0.0');\n resetTimer();\n\n return {\n server,\n resetTimer,\n destroy: () => {\n if (idleTimer) clearTimeout(idleTimer);\n pendingConns.forEach(s => s.destroy());\n server.close();\n },\n };\n}\n","export interface ServiceConfig {\n name: string;\n cwd: string;\n cmd: string;\n args: string[];\n type: 'api' | 'web';\n port: number;\n phase: number;\n maxMem?: number;\n preBuild?: string;\n watchBuild?: string;\n nodeArgs?: string[];\n extraEnv?: Record<string, string>;\n}\n\nexport interface LazyConfig {\n alwaysOn: string[];\n timeout?: number;\n}\n\nexport interface ProxyConfig {\n provider: string;\n routes: Record<string, string>;\n confPath?: string;\n host?: string;\n tls?: boolean;\n entrypoint?: string;\n}\n\nexport interface DevStackConfig {\n name: string;\n icon?: string;\n envFile?: string;\n env?: Record<string, string>;\n services: ServiceConfig[];\n lazy?: LazyConfig;\n proxy?: ProxyConfig;\n}\n\nexport function defineConfig(config: DevStackConfig): DevStackConfig {\n return config;\n}\n"],"mappings":"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","names":["React","join","existsSync","resolve","existsSync","existsSync","writeFileSync","join","join","existsSync","writeFileSync","useEffect","useState","useCallback","useRef","Box","Text","spawn","join","resolve","existsSync","existsSync","resolve","join","spawn","mgr","useState","useCallback","useEffect","useRef","useEffect","useEffect","useEffect","Box","Text","jsx","jsxs","Text","useEffect","Box","Box","Text","jsx","jsxs","useState","Box","Text","useInput","jsx","jsxs","useState","Box","Text","useInput","jsx","jsxs","net","net","jsx","jsxs","useState","useRef","useEffect","useCallback","Box","Text","join","React"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"installer.d.ts","sourceRoot":"","sources":["../../src/process/installer.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,OAAO,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,cAAc,CAC5B,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EACxC,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,GAC5B,OAAO,CAAC,OAAO,CAAC,
|
|
1
|
+
{"version":3,"file":"installer.d.ts","sourceRoot":"","sources":["../../src/process/installer.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,OAAO,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,cAAc,CAC5B,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EACxC,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,GAC5B,OAAO,CAAC,OAAO,CAAC,CAgClB;AAED,wBAAsB,YAAY,CAChC,KAAK,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,CAAC,EACxE,WAAW,EAAE,MAAM,EACnB,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,IAAI,GAC1C,OAAO,CAAC,aAAa,EAAE,CAAC,CAkB1B"}
|
package/dist/tui/App.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"App.d.ts","sourceRoot":"","sources":["../../src/tui/App.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,KAAK,EAAE,mBAAmB,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAe/E,UAAU,KAAK;IACb,MAAM,EAAE,cAAc,CAAC;IACvB,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,QAAQ,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,mBAAmB,GAAG,IAAI,CAAC;IAC1C,SAAS,EAAE,SAAS,GAAG,IAAI,CAAC;CAC7B;AAED,wBAAgB,GAAG,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,EAAE,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,EAAE,KAAK,
|
|
1
|
+
{"version":3,"file":"App.d.ts","sourceRoot":"","sources":["../../src/tui/App.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,KAAK,EAAE,mBAAmB,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAe/E,UAAU,KAAK;IACb,MAAM,EAAE,cAAc,CAAC;IACvB,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,QAAQ,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,mBAAmB,GAAG,IAAI,CAAC;IAC1C,SAAS,EAAE,SAAS,GAAG,IAAI,CAAC;CAC7B;AAED,wBAAgB,GAAG,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,EAAE,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,EAAE,KAAK,2CAgKzG"}
|
package/dist/tui/LogsPanel.d.ts
CHANGED
|
@@ -8,7 +8,9 @@ interface Props {
|
|
|
8
8
|
maxNameLen: number;
|
|
9
9
|
height: number;
|
|
10
10
|
focused: boolean;
|
|
11
|
+
scrollOffset: number;
|
|
12
|
+
resetScroll: () => void;
|
|
11
13
|
}
|
|
12
|
-
export declare function LogsPanel({ logs, filter, searchTerm, paused, showTimestamps, maxNameLen, height, focused }: Props): import("react/jsx-runtime").JSX.Element;
|
|
14
|
+
export declare function LogsPanel({ logs, filter, searchTerm, paused, showTimestamps, maxNameLen, height, focused, scrollOffset, resetScroll }: Props): import("react/jsx-runtime").JSX.Element;
|
|
13
15
|
export {};
|
|
14
16
|
//# sourceMappingURL=LogsPanel.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LogsPanel.d.ts","sourceRoot":"","sources":["../../src/tui/LogsPanel.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AAG7D,UAAU,KAAK;IACb,IAAI,EAAE,QAAQ,EAAE,CAAC;IACjB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,MAAM,EAAE,OAAO,CAAC;IAChB,cAAc,EAAE,OAAO,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"LogsPanel.d.ts","sourceRoot":"","sources":["../../src/tui/LogsPanel.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AAG7D,UAAU,KAAK;IACb,IAAI,EAAE,QAAQ,EAAE,CAAC;IACjB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,MAAM,EAAE,OAAO,CAAC;IAChB,cAAc,EAAE,OAAO,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,IAAI,CAAC;CACzB;AAED,wBAAgB,SAAS,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,EAAE,KAAK,2CAsD5I"}
|
package/dist/tui/StatsPanel.d.ts
CHANGED
|
@@ -7,7 +7,9 @@ interface Props {
|
|
|
7
7
|
maxNameLen: number;
|
|
8
8
|
height: number;
|
|
9
9
|
focused: boolean;
|
|
10
|
+
scrollOffset: number;
|
|
11
|
+
resetScroll: () => void;
|
|
10
12
|
}
|
|
11
|
-
export declare function StatsPanel({ states, stats, sortMode, maxNameLen, height, focused }: Props): import("react/jsx-runtime").JSX.Element;
|
|
13
|
+
export declare function StatsPanel({ states, stats, sortMode, maxNameLen, height, focused, scrollOffset, resetScroll }: Props): import("react/jsx-runtime").JSX.Element;
|
|
12
14
|
export {};
|
|
13
15
|
//# sourceMappingURL=StatsPanel.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StatsPanel.d.ts","sourceRoot":"","sources":["../../src/tui/StatsPanel.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAIjE,UAAU,KAAK;IACb,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IAClC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"StatsPanel.d.ts","sourceRoot":"","sources":["../../src/tui/StatsPanel.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAIjE,UAAU,KAAK;IACb,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IAClC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,IAAI,CAAC;CACzB;AAuBD,wBAAgB,UAAU,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,EAAE,KAAK,2CA2FpH"}
|
|
@@ -9,6 +9,8 @@ export interface KeyState {
|
|
|
9
9
|
showTimestamps: boolean;
|
|
10
10
|
sortIdx: number;
|
|
11
11
|
proxyEnabled: boolean;
|
|
12
|
+
logsScrollOffset: number;
|
|
13
|
+
statsScrollOffset: number;
|
|
12
14
|
}
|
|
13
15
|
export declare function useKeyBindings(opts: {
|
|
14
16
|
onQuit: () => void;
|
|
@@ -19,6 +21,8 @@ export declare function useKeyBindings(opts: {
|
|
|
19
21
|
setFilter: (f: string | null) => void;
|
|
20
22
|
setSearch: (t: string | null) => void;
|
|
21
23
|
sortMode: "name" | "mem" | "errors";
|
|
24
|
+
resetLogsScroll: () => void;
|
|
25
|
+
resetStatsScroll: () => void;
|
|
22
26
|
panel: Panel;
|
|
23
27
|
modal: Modal;
|
|
24
28
|
logFilter: string | null;
|
|
@@ -27,5 +31,7 @@ export declare function useKeyBindings(opts: {
|
|
|
27
31
|
showTimestamps: boolean;
|
|
28
32
|
sortIdx: number;
|
|
29
33
|
proxyEnabled: boolean;
|
|
34
|
+
logsScrollOffset: number;
|
|
35
|
+
statsScrollOffset: number;
|
|
30
36
|
};
|
|
31
37
|
//# sourceMappingURL=useKeyBindings.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useKeyBindings.d.ts","sourceRoot":"","sources":["../../../src/tui/hooks/useKeyBindings.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,KAAK,GAAG,MAAM,GAAG,QAAQ,GAAG,SAAS,GAAG,MAAM,GAAG,QAAQ,CAAC;AACtE,MAAM,MAAM,KAAK,GAAG,MAAM,GAAG,OAAO,CAAC;AAErC,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,KAAK,CAAC;IACb,KAAK,EAAE,KAAK,CAAC;IACb,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,EAAE,OAAO,CAAC;IACpB,cAAc,EAAE,OAAO,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"useKeyBindings.d.ts","sourceRoot":"","sources":["../../../src/tui/hooks/useKeyBindings.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,KAAK,GAAG,MAAM,GAAG,QAAQ,GAAG,SAAS,GAAG,MAAM,GAAG,QAAQ,CAAC;AACtE,MAAM,MAAM,KAAK,GAAG,MAAM,GAAG,OAAO,CAAC;AAErC,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,KAAK,CAAC;IACb,KAAK,EAAE,KAAK,CAAC;IACb,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,EAAE,OAAO,CAAC;IACpB,cAAc,EAAE,OAAO,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,OAAO,CAAC;IACtB,gBAAgB,EAAE,MAAM,CAAC;IACzB,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAID,wBAAgB,cAAc,CAAC,IAAI,EAAE;IACnC,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,WAAW,EAAE,MAAM,IAAI,CAAC;IACxB,aAAa,EAAE,MAAM,IAAI,CAAC;CAC3B;sBAOsC,KAAK;mBACR,MAAM,GAAG,IAAI;mBACb,MAAM,GAAG,IAAI;;;;WA3BxC,KAAK;WACL,KAAK;eACD,MAAM,GAAG,IAAI;gBACZ,MAAM,GAAG,IAAI;gBACb,OAAO;oBACH,OAAO;aACd,MAAM;kBACD,OAAO;sBACH,MAAM;uBACL,MAAM;EAgH1B"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gachlab/devup",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Dev stack runner with TUI, lazy proxy, and reverse proxy support",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -44,24 +44,33 @@
|
|
|
44
44
|
"build": "tsup && tsc --emitDeclarationOnly",
|
|
45
45
|
"dev": "tsup --watch",
|
|
46
46
|
"prepublishOnly": "npm run build",
|
|
47
|
-
"test": "node --import tsx --test \"tests/**/*.test.ts\"",
|
|
48
|
-
"test:unit": "node --import tsx --test \"tests/unit/**/*.test.ts\"",
|
|
49
|
-
"test:integration": "node --import tsx --test \"tests/integration/**/*.test.ts\"",
|
|
50
|
-
"test:watch": "node --import tsx --test --watch \"tests/**/*.test.ts\"",
|
|
51
|
-
"test:coverage": "node --import tsx --test --experimental-test-coverage \"tests/**/*.test.ts\""
|
|
47
|
+
"test": "node --import tsx --test \"tests/**/*.test.ts\" \"tests/**/*.test.tsx\"",
|
|
48
|
+
"test:unit": "node --import tsx --test --experimental-test-coverage \"tests/unit/**/*.test.ts\" \"tests/unit/**/*.test.tsx\"",
|
|
49
|
+
"test:integration": "node --import tsx --test --experimental-test-coverage \"tests/integration/**/*.test.ts\"",
|
|
50
|
+
"test:watch": "node --import tsx --test --watch \"tests/**/*.test.ts\" \"tests/**/*.test.tsx\"",
|
|
51
|
+
"test:coverage": "node --import tsx --test --experimental-test-coverage \"tests/**/*.test.ts\" \"tests/**/*.test.tsx\""
|
|
52
52
|
},
|
|
53
53
|
"dependencies": {
|
|
54
54
|
"ink": "7.0.1",
|
|
55
55
|
"react": "19.2.5"
|
|
56
56
|
},
|
|
57
57
|
"devDependencies": {
|
|
58
|
+
"@testing-library/dom": "^10.4.1",
|
|
59
|
+
"@testing-library/react": "^16.3.2",
|
|
60
|
+
"@types/jest": "^30.0.0",
|
|
58
61
|
"@types/node": "22.15.3",
|
|
59
62
|
"@types/react": "19.2.14",
|
|
63
|
+
"ink-testing-library": "^4.0.0",
|
|
64
|
+
"react-dom": "^19.2.5",
|
|
60
65
|
"tsup": "8.5.1",
|
|
61
66
|
"tsx": "4.19.4",
|
|
62
67
|
"typescript": "6.0.3"
|
|
63
68
|
},
|
|
64
69
|
"engines": {
|
|
65
70
|
"node": ">=22"
|
|
71
|
+
},
|
|
72
|
+
"publishConfig": {
|
|
73
|
+
"access": "public",
|
|
74
|
+
"registry": "https://registry.npmjs.org/"
|
|
66
75
|
}
|
|
67
|
-
}
|
|
76
|
+
}
|