@revealui/setup 0.3.4 → 0.3.6

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 CHANGED
@@ -1,3 +1,148 @@
1
+ // src/bootstrap/index.ts
2
+ function richTextDoc(...nodes) {
3
+ return {
4
+ root: {
5
+ type: "root",
6
+ children: nodes,
7
+ direction: "ltr",
8
+ format: "",
9
+ indent: 0,
10
+ version: 1
11
+ }
12
+ };
13
+ }
14
+ function heading(text, tag = "h2") {
15
+ return {
16
+ type: "heading",
17
+ children: [{ type: "text", detail: 0, format: 0, mode: "normal", style: "", text, version: 1 }],
18
+ direction: "ltr",
19
+ format: "",
20
+ indent: 0,
21
+ tag,
22
+ version: 1
23
+ };
24
+ }
25
+ function paragraph(text) {
26
+ return {
27
+ type: "paragraph",
28
+ children: [{ type: "text", detail: 0, format: 0, mode: "normal", style: "", text, version: 1 }],
29
+ direction: "ltr",
30
+ format: "",
31
+ indent: 0,
32
+ textFormat: 0,
33
+ textStyle: "",
34
+ version: 1
35
+ };
36
+ }
37
+ var SEED_PAGES = [
38
+ {
39
+ title: "Home",
40
+ slug: "home",
41
+ path: "/",
42
+ layout: [
43
+ {
44
+ blockType: "content",
45
+ columns: [
46
+ {
47
+ size: "full",
48
+ richText: richTextDoc(
49
+ heading("Welcome to RevealUI"),
50
+ paragraph(
51
+ "Your agentic business runtime is ready. Visit /admin to manage content, configure collections, and build your application."
52
+ )
53
+ )
54
+ }
55
+ ]
56
+ }
57
+ ]
58
+ }
59
+ ];
60
+ async function bootstrap(options) {
61
+ const { revealui, admin, seed = true } = options;
62
+ try {
63
+ const existing = await revealui.find({
64
+ collection: "users",
65
+ limit: 1,
66
+ depth: 0
67
+ });
68
+ if (existing.totalDocs > 0) {
69
+ return {
70
+ status: "locked",
71
+ message: "Setup already completed. Users exist."
72
+ };
73
+ }
74
+ } catch (err) {
75
+ return {
76
+ status: "error",
77
+ message: "Database connection failed. Check POSTGRES_URL or DATABASE_URL.",
78
+ error: err instanceof Error ? err.message : String(err)
79
+ };
80
+ }
81
+ if (!(admin.email && admin.password)) {
82
+ return {
83
+ status: "error",
84
+ message: "Admin email and password are required."
85
+ };
86
+ }
87
+ if (admin.password.length < 12) {
88
+ return {
89
+ status: "error",
90
+ message: "Admin password must be at least 12 characters."
91
+ };
92
+ }
93
+ try {
94
+ await revealui.create({
95
+ collection: "users",
96
+ data: {
97
+ name: admin.name ?? "Admin",
98
+ email: admin.email,
99
+ password: admin.password,
100
+ role: "owner",
101
+ roles: ["super-admin"]
102
+ }
103
+ });
104
+ } catch (err) {
105
+ const pgCode = err.code;
106
+ if (pgCode === "23505") {
107
+ return {
108
+ status: "error",
109
+ message: "A user with that email already exists."
110
+ };
111
+ }
112
+ return {
113
+ status: "error",
114
+ message: "Failed to create admin user.",
115
+ error: err instanceof Error ? err.message : String(err)
116
+ };
117
+ }
118
+ let seeded = false;
119
+ if (seed) {
120
+ try {
121
+ for (const page of SEED_PAGES) {
122
+ const existing = await revealui.find({
123
+ collection: "pages",
124
+ where: { slug: { equals: page.slug } },
125
+ limit: 1
126
+ });
127
+ if (existing.docs.length === 0) {
128
+ await revealui.create({
129
+ collection: "pages",
130
+ data: page
131
+ });
132
+ }
133
+ }
134
+ seeded = true;
135
+ } catch {
136
+ }
137
+ }
138
+ return {
139
+ status: "created",
140
+ message: `Admin user created${seeded ? " and content seeded" : ""}. Sign in at /admin.`,
141
+ user: { email: admin.email, role: "owner" },
142
+ seeded
143
+ };
144
+ }
145
+
1
146
  // src/environment/generators.ts
2
147
  import { randomBytes } from "crypto";
3
148
  function generateSecret(length = 32) {
@@ -5,10 +150,15 @@ function generateSecret(length = 32) {
5
150
  }
6
151
  function generatePassword(length = 16) {
7
152
  const chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*";
153
+ const maxValid = 256 - 256 % chars.length;
8
154
  let password = "";
9
- const randomValues = randomBytes(length);
10
- for (let i = 0; i < length; i++) {
11
- password += chars[randomValues[i] % chars.length];
155
+ while (password.length < length) {
156
+ const buf = randomBytes(length - password.length + 16);
157
+ for (let i = 0; i < buf.length && password.length < length; i++) {
158
+ if (buf[i] < maxValid) {
159
+ password += chars[buf[i] % chars.length];
160
+ }
161
+ }
12
162
  }
13
163
  return password;
14
164
  }
@@ -456,18 +606,370 @@ async function generateSecrets(envPath, logger2) {
456
606
  await writeFile(envPath, content);
457
607
  logger2.success("Generated REVEALUI_SECRET");
458
608
  }
609
+
610
+ // src/system-tune/detect.ts
611
+ import { execSync } from "child_process";
612
+ import { existsSync, readFileSync } from "fs";
613
+ import { arch, cpus, freemem, homedir, platform, release, totalmem } from "os";
614
+ import { join as join2 } from "path";
615
+ function detectPlatformClass() {
616
+ const p = platform();
617
+ if (p === "linux") {
618
+ try {
619
+ const procVersion = readFileSync("/proc/version", "utf8").toLowerCase();
620
+ if (procVersion.includes("microsoft") || procVersion.includes("wsl")) {
621
+ return "wsl2";
622
+ }
623
+ } catch {
624
+ }
625
+ try {
626
+ if (existsSync("/.dockerenv")) return "docker";
627
+ const cgroup = readFileSync("/proc/1/cgroup", "utf8");
628
+ if (cgroup.includes("docker") || cgroup.includes("containerd")) return "docker";
629
+ } catch {
630
+ }
631
+ try {
632
+ const dmiProduct = readFileSync("/sys/class/dmi/id/product_name", "utf8").trim().toLowerCase();
633
+ if (dmiProduct.includes("virtual") || dmiProduct.includes("kvm") || dmiProduct.includes("xen") || dmiProduct.includes("hvm")) {
634
+ return "cloud-vm";
635
+ }
636
+ } catch {
637
+ }
638
+ return "linux";
639
+ }
640
+ if (p === "darwin") return "macos";
641
+ if (p === "win32") return "windows";
642
+ return "unknown";
643
+ }
644
+ function detectDistro() {
645
+ try {
646
+ const osRelease = readFileSync("/etc/os-release", "utf8");
647
+ const match = osRelease.match(/^PRETTY_NAME="?([^"\n]+)"?/m);
648
+ return match?.[1];
649
+ } catch {
650
+ return void 0;
651
+ }
652
+ }
653
+ function detectMemory() {
654
+ const p = platform();
655
+ if (p === "linux") {
656
+ try {
657
+ const meminfo = readFileSync("/proc/meminfo", "utf8");
658
+ const parse = (key) => {
659
+ const match = meminfo.match(new RegExp(`^${key}:\\s+(\\d+)`, "m"));
660
+ return match ? Number.parseInt(match[1], 10) * 1024 : 0;
661
+ };
662
+ return {
663
+ totalBytes: parse("MemTotal"),
664
+ freeBytes: parse("MemAvailable") || parse("MemFree"),
665
+ swapTotalBytes: parse("SwapTotal"),
666
+ swapFreeBytes: parse("SwapFree")
667
+ };
668
+ } catch {
669
+ }
670
+ }
671
+ return {
672
+ totalBytes: totalmem(),
673
+ freeBytes: freemem(),
674
+ swapTotalBytes: 0,
675
+ swapFreeBytes: 0
676
+ };
677
+ }
678
+ function detectCpu() {
679
+ const cores = cpus();
680
+ const model = cores[0]?.model ?? "unknown";
681
+ const logicalCores = cores.length;
682
+ let physicalCores = logicalCores;
683
+ const p = platform();
684
+ if (p === "linux") {
685
+ try {
686
+ const output = execSync('grep "^cpu cores" /proc/cpuinfo | head -1', {
687
+ encoding: "utf8",
688
+ timeout: 2e3
689
+ });
690
+ const match = output.match(/:\s*(\d+)/);
691
+ if (match) physicalCores = Number.parseInt(match[1], 10);
692
+ } catch {
693
+ }
694
+ } else if (p === "darwin") {
695
+ try {
696
+ const output = execSync("sysctl -n hw.physicalcpu", { encoding: "utf8", timeout: 2e3 });
697
+ physicalCores = Number.parseInt(output.trim(), 10) || logicalCores;
698
+ } catch {
699
+ }
700
+ }
701
+ return { model, physicalCores, logicalCores };
702
+ }
703
+ function detectDisk() {
704
+ const p = platform();
705
+ const target = process.cwd();
706
+ if (p === "linux" || p === "darwin") {
707
+ try {
708
+ const output = execSync(`df -B1 "${target}" | tail -1`, { encoding: "utf8", timeout: 2e3 });
709
+ const parts = output.trim().split(/\s+/);
710
+ if (parts.length >= 4) {
711
+ return {
712
+ totalBytes: Number.parseInt(parts[1], 10) || 0,
713
+ freeBytes: Number.parseInt(parts[3], 10) || 0
714
+ };
715
+ }
716
+ } catch {
717
+ }
718
+ }
719
+ return { totalBytes: 0, freeBytes: 0 };
720
+ }
721
+ function detectExistingConfigs() {
722
+ const home = homedir();
723
+ let wslconfig = false;
724
+ try {
725
+ const windowsUser = execSync('cmd.exe /c "echo %USERPROFILE%" 2>/dev/null', {
726
+ encoding: "utf8",
727
+ timeout: 3e3
728
+ }).trim();
729
+ const wslPath = windowsUser.replace(/\\/g, "/").replace(/^([A-Z]):/i, (_, d) => `/mnt/${d.toLowerCase()}`);
730
+ wslconfig = existsSync(join2(wslPath, ".wslconfig"));
731
+ } catch {
732
+ wslconfig = existsSync(join2(home, ".wslconfig"));
733
+ }
734
+ let earlyoom = false;
735
+ try {
736
+ const result = execSync("systemctl is-enabled earlyoom 2>/dev/null", {
737
+ encoding: "utf8",
738
+ timeout: 2e3
739
+ });
740
+ earlyoom = result.trim() === "enabled";
741
+ } catch {
742
+ earlyoom = false;
743
+ }
744
+ let dockerAutostart = false;
745
+ try {
746
+ const result = execSync("systemctl is-enabled docker 2>/dev/null", {
747
+ encoding: "utf8",
748
+ timeout: 2e3
749
+ });
750
+ dockerAutostart = result.trim() === "enabled";
751
+ } catch {
752
+ dockerAutostart = false;
753
+ }
754
+ const nodeOptions = process.env.NODE_OPTIONS ?? null;
755
+ return { wslconfig, earlyoom, dockerAutostart, nodeOptions };
756
+ }
757
+ function detectSystem() {
758
+ return {
759
+ os: {
760
+ platform: platform(),
761
+ release: release(),
762
+ arch: arch(),
763
+ distro: detectDistro()
764
+ },
765
+ platformClass: detectPlatformClass(),
766
+ memory: detectMemory(),
767
+ cpu: detectCpu(),
768
+ disk: detectDisk(),
769
+ existingConfigs: detectExistingConfigs()
770
+ };
771
+ }
772
+
773
+ // src/system-tune/profiles/wsl-low-ram.json
774
+ var wsl_low_ram_default = {
775
+ $schema: "../profile-schema.json",
776
+ id: "wsl-low-ram",
777
+ name: "WSL2 Low-RAM Host",
778
+ description: "Safe defaults for WSL2 on hosts with \u22648 GB RAM. Prevents the VM from starving Windows by capping memory, disabling aggressive reclaim, and keeping Docker off by default.",
779
+ version: "0.1.0",
780
+ origin: "2026-04-13 crash postmortem: WSL on 7.3 GB host claimed ~6 GB, starving Windows. Hand-authored fix captured as seed profile.",
781
+ match: {
782
+ platform: "wsl2",
783
+ maxHostRamGb: 8
784
+ },
785
+ tune: {
786
+ wslconfig: {
787
+ memory: "4GB",
788
+ processors: 2,
789
+ swap: "2GB",
790
+ vmIdleTimeout: -1,
791
+ autoMemoryReclaim: "disabled",
792
+ networkingMode: "mirrored"
793
+ },
794
+ node: {
795
+ maxOldSpaceSize: 2048
796
+ },
797
+ pnpm: {
798
+ childConcurrency: 2
799
+ },
800
+ turbo: {
801
+ concurrency: 2
802
+ },
803
+ vitest: {
804
+ maxThreads: 2
805
+ },
806
+ earlyoom: {
807
+ enabled: true,
808
+ memThreshold: 5,
809
+ swapThreshold: 10,
810
+ prefer: "turbo|biome|vitest|tsc|esbuild"
811
+ },
812
+ docker: {
813
+ autostart: false
814
+ }
815
+ }
816
+ };
817
+
818
+ // src/system-tune/profiles.ts
819
+ var PROFILES = [wsl_low_ram_default];
820
+
821
+ // src/system-tune/plan.ts
822
+ function matchProfile(system) {
823
+ const ramGb = system.memory.totalBytes / (1024 * 1024 * 1024);
824
+ for (const profile of PROFILES) {
825
+ if (profile.match.platform !== system.platformClass) continue;
826
+ if (profile.match.maxHostRamGb !== void 0 && ramGb > profile.match.maxHostRamGb) continue;
827
+ if (profile.match.minHostRamGb !== void 0 && ramGb < profile.match.minHostRamGb) continue;
828
+ return profile;
829
+ }
830
+ return null;
831
+ }
832
+ function generateWslActions(profile, system) {
833
+ const actions = [];
834
+ const wsl = profile.tune.wslconfig;
835
+ if (!wsl) return actions;
836
+ const entries = [];
837
+ if (wsl.memory) entries.push(["memory", wsl.memory]);
838
+ if (wsl.processors !== void 0) entries.push(["processors", String(wsl.processors)]);
839
+ if (wsl.swap) entries.push(["swap", wsl.swap]);
840
+ if (wsl.vmIdleTimeout !== void 0) entries.push(["vmIdleTimeout", String(wsl.vmIdleTimeout)]);
841
+ if (wsl.autoMemoryReclaim) entries.push(["autoMemoryReclaim", wsl.autoMemoryReclaim]);
842
+ if (wsl.networkingMode) entries.push(["networkingMode", wsl.networkingMode]);
843
+ if (entries.length > 0) {
844
+ const desired = entries.map(([k, v]) => `${k}=${v}`).join(", ");
845
+ actions.push({
846
+ target: ".wslconfig [wsl2]",
847
+ current: system.existingConfigs.wslconfig ? "(exists, values unknown)" : null,
848
+ desired,
849
+ privileged: false,
850
+ description: `Set WSL2 config: ${desired}`
851
+ });
852
+ }
853
+ return actions;
854
+ }
855
+ function generateNodeActions(profile, system) {
856
+ const actions = [];
857
+ const node = profile.tune.node;
858
+ if (!node?.maxOldSpaceSize) return actions;
859
+ const desired = `--max-old-space-size=${node.maxOldSpaceSize}`;
860
+ const current = system.existingConfigs.nodeOptions;
861
+ const alreadySet = current?.includes("max-old-space-size") ?? false;
862
+ if (!alreadySet) {
863
+ actions.push({
864
+ target: "NODE_OPTIONS",
865
+ current,
866
+ desired: current ? `${current} ${desired}` : desired,
867
+ privileged: false,
868
+ description: `Add ${desired} to NODE_OPTIONS in shell profile`
869
+ });
870
+ }
871
+ return actions;
872
+ }
873
+ function generateEarlyoomActions(profile, system) {
874
+ const actions = [];
875
+ const oom = profile.tune.earlyoom;
876
+ if (!oom?.enabled) return actions;
877
+ if (!system.existingConfigs.earlyoom) {
878
+ const args = [`-m ${oom.memThreshold ?? 5}`, `-s ${oom.swapThreshold ?? 10}`];
879
+ if (oom.prefer) args.push(`--prefer '${oom.prefer}'`);
880
+ actions.push({
881
+ target: "/etc/default/earlyoom",
882
+ current: null,
883
+ desired: `EARLYOOM_ARGS="${args.join(" ")}"`,
884
+ privileged: true,
885
+ description: `Install and configure earlyoom (kill memory hogs before OOM killer)`
886
+ });
887
+ }
888
+ return actions;
889
+ }
890
+ function generateDockerActions(profile, system) {
891
+ const actions = [];
892
+ const docker = profile.tune.docker;
893
+ if (docker === void 0) return actions;
894
+ if (!docker.autostart && system.existingConfigs.dockerAutostart) {
895
+ actions.push({
896
+ target: "systemctl docker",
897
+ current: "enabled (autostart)",
898
+ desired: "disabled (on-demand via sudo systemctl start docker)",
899
+ privileged: true,
900
+ description: "Disable Docker autostart to save ~200-400 MB RAM on boot"
901
+ });
902
+ }
903
+ return actions;
904
+ }
905
+ function generateConcurrencyActions(profile) {
906
+ const actions = [];
907
+ if (profile.tune.pnpm?.childConcurrency) {
908
+ actions.push({
909
+ target: ".npmrc or pnpm config",
910
+ current: null,
911
+ desired: `child-concurrency=${profile.tune.pnpm.childConcurrency}`,
912
+ privileged: false,
913
+ description: `Limit pnpm child concurrency to ${profile.tune.pnpm.childConcurrency}`
914
+ });
915
+ }
916
+ if (profile.tune.turbo?.concurrency) {
917
+ actions.push({
918
+ target: "turbo.json or TURBO_CONCURRENCY",
919
+ current: null,
920
+ desired: `concurrency=${profile.tune.turbo.concurrency}`,
921
+ privileged: false,
922
+ description: `Limit Turbo concurrency to ${profile.tune.turbo.concurrency}`
923
+ });
924
+ }
925
+ if (profile.tune.vitest?.maxThreads) {
926
+ actions.push({
927
+ target: "vitest.config poolOptions.threads.maxThreads",
928
+ current: null,
929
+ desired: `maxThreads=${profile.tune.vitest.maxThreads}`,
930
+ privileged: false,
931
+ description: `Limit Vitest threads to ${profile.tune.vitest.maxThreads}`
932
+ });
933
+ }
934
+ return actions;
935
+ }
936
+ function generatePlan(system, profile) {
937
+ const actions = [
938
+ ...generateWslActions(profile, system),
939
+ ...generateNodeActions(profile, system),
940
+ ...generateEarlyoomActions(profile, system),
941
+ ...generateDockerActions(profile, system),
942
+ ...generateConcurrencyActions(profile)
943
+ ];
944
+ return {
945
+ profileId: profile.id,
946
+ system,
947
+ actions,
948
+ isNoop: actions.length === 0
949
+ };
950
+ }
951
+ function generateAutoplan(system) {
952
+ const profile = matchProfile(system);
953
+ if (!profile) return null;
954
+ return generatePlan(system, profile);
955
+ }
459
956
  export {
460
957
  OPTIONAL_ENV_VARS,
958
+ PROFILES,
461
959
  REQUIRED_ENV_VARS,
960
+ bootstrap,
462
961
  createLogger,
962
+ detectSystem,
963
+ generateAutoplan,
463
964
  generatePassword,
965
+ generatePlan,
464
966
  generateSecret,
465
967
  handleASTParseError,
466
968
  logger,
969
+ matchProfile,
467
970
  parseEnvContent,
468
971
  setupEnvironment,
469
972
  updateEnvValue,
470
973
  validateEnv,
471
974
  validators
472
975
  };
473
- //# sourceMappingURL=index.js.map
@@ -0,0 +1,152 @@
1
+ /**
2
+ * System Tune Types
3
+ *
4
+ * Shared types for hardware detection, tuning profiles, and plan generation.
5
+ */
6
+ type PlatformClass = 'wsl2' | 'linux' | 'macos' | 'windows' | 'docker' | 'cloud-vm' | 'unknown';
7
+ interface SystemInfo {
8
+ /** OS/distro/kernel identification */
9
+ os: {
10
+ platform: NodeJS.Platform;
11
+ release: string;
12
+ arch: string;
13
+ distro?: string;
14
+ };
15
+ /** Detected platform class */
16
+ platformClass: PlatformClass;
17
+ /** Memory in bytes */
18
+ memory: {
19
+ totalBytes: number;
20
+ freeBytes: number;
21
+ swapTotalBytes: number;
22
+ swapFreeBytes: number;
23
+ };
24
+ /** CPU info */
25
+ cpu: {
26
+ model: string;
27
+ physicalCores: number;
28
+ logicalCores: number;
29
+ };
30
+ /** Disk info for the working directory */
31
+ disk: {
32
+ totalBytes: number;
33
+ freeBytes: number;
34
+ };
35
+ /** Existing configs already present */
36
+ existingConfigs: {
37
+ wslconfig: boolean;
38
+ earlyoom: boolean;
39
+ dockerAutostart: boolean;
40
+ nodeOptions: string | null;
41
+ };
42
+ }
43
+ interface WslConfigTune {
44
+ memory?: string;
45
+ processors?: number;
46
+ swap?: string;
47
+ vmIdleTimeout?: number;
48
+ autoMemoryReclaim?: string;
49
+ networkingMode?: string;
50
+ }
51
+ interface TuneValues {
52
+ wslconfig?: WslConfigTune;
53
+ node?: {
54
+ maxOldSpaceSize?: number;
55
+ };
56
+ pnpm?: {
57
+ childConcurrency?: number;
58
+ };
59
+ turbo?: {
60
+ concurrency?: number;
61
+ };
62
+ vitest?: {
63
+ maxThreads?: number;
64
+ };
65
+ earlyoom?: {
66
+ enabled?: boolean;
67
+ memThreshold?: number;
68
+ swapThreshold?: number;
69
+ prefer?: string;
70
+ };
71
+ docker?: {
72
+ autostart?: boolean;
73
+ };
74
+ macos?: {
75
+ maxFiles?: number;
76
+ spotlightExclusions?: string[];
77
+ };
78
+ windows?: {
79
+ defenderExclusions?: string[];
80
+ longPaths?: boolean;
81
+ };
82
+ }
83
+ interface TuneProfile {
84
+ id: string;
85
+ name: string;
86
+ description: string;
87
+ version: string;
88
+ origin?: string;
89
+ match: {
90
+ platform: PlatformClass;
91
+ maxHostRamGb?: number;
92
+ minHostRamGb?: number;
93
+ };
94
+ tune: TuneValues;
95
+ }
96
+ interface PlanAction {
97
+ /** What file or setting is being changed */
98
+ target: string;
99
+ /** What the current value is (null if not set) */
100
+ current: string | null;
101
+ /** What the new value will be */
102
+ desired: string;
103
+ /** Whether this requires elevated privileges */
104
+ privileged: boolean;
105
+ /** Human-readable description */
106
+ description: string;
107
+ }
108
+ interface TunePlan {
109
+ /** Profile that generated this plan */
110
+ profileId: string;
111
+ /** Detected system info */
112
+ system: SystemInfo;
113
+ /** Actions to take */
114
+ actions: PlanAction[];
115
+ /** Whether all actions are no-ops (system already tuned) */
116
+ isNoop: boolean;
117
+ }
118
+
119
+ /**
120
+ * System Detection Layer
121
+ *
122
+ * Scans the host's hardware and platform to produce a SystemInfo snapshot.
123
+ * This is the "read" side — no mutations, only observation.
124
+ */
125
+
126
+ /** Scan the current host and return a SystemInfo snapshot. */
127
+ declare function detectSystem(): SystemInfo;
128
+
129
+ /**
130
+ * Plan Generator
131
+ *
132
+ * Pure function: (detected system state, profile) → plan of actions.
133
+ * No I/O — only computes the diff between current and desired state.
134
+ */
135
+
136
+ /** Find the best matching profile for the detected system. */
137
+ declare function matchProfile(system: SystemInfo): TuneProfile | null;
138
+ /** Generate a tuning plan from detected system state and a profile. */
139
+ declare function generatePlan(system: SystemInfo, profile: TuneProfile): TunePlan;
140
+ /** Detect system, find matching profile, and generate plan. */
141
+ declare function generateAutoplan(system: SystemInfo): TunePlan | null;
142
+
143
+ /**
144
+ * Built-in Tuning Profiles
145
+ *
146
+ * Profiles are ordered by specificity — the first match wins.
147
+ * Add new profiles here, most specific first.
148
+ */
149
+
150
+ declare const PROFILES: TuneProfile[];
151
+
152
+ export { PROFILES, type PlanAction, type PlatformClass, type SystemInfo, type TunePlan, type TuneProfile, type TuneValues, type WslConfigTune, detectSystem, generateAutoplan, generatePlan, matchProfile };