@pushpalsdev/cli 1.0.19 → 1.0.21
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/pushpals-cli.js +14 -32
- package/package.json +1 -1
- package/runtime/configs/backend.toml +1 -1
- package/runtime/configs/default.toml +1 -1
- package/runtime/sandbox/apps/workerpals/src/backends/backend_config.ts +25 -14
- package/runtime/sandbox/configs/backend.toml +1 -1
- package/runtime/sandbox/configs/default.toml +1 -1
- package/runtime/sandbox/packages/shared/src/client_preflight.ts +1 -12
- package/runtime/sandbox/packages/shared/src/config.ts +15 -36
- package/runtime/sandbox/packages/shared/src/index.ts +1 -0
- package/runtime/sandbox/packages/shared/src/localbuddy_runtime.ts +14 -29
package/dist/pushpals-cli.js
CHANGED
|
@@ -101,7 +101,6 @@ function normalizeLoopbackHttpUrl(value, fallbackPort) {
|
|
|
101
101
|
// ../shared/src/config.ts
|
|
102
102
|
var PROJECT_ROOT = resolve(import.meta.dir, "..", "..", "..");
|
|
103
103
|
var DEFAULT_CONFIG_DIR = "configs";
|
|
104
|
-
var LEGACY_CONFIG_DIR = "config";
|
|
105
104
|
var TRUTHY = new Set(["1", "true", "yes", "on"]);
|
|
106
105
|
var FALSY = new Set(["0", "false", "no", "off"]);
|
|
107
106
|
var DEFAULT_WORKERPALS_QUALITY_CRITIC_MIN_SCORE = 8;
|
|
@@ -114,6 +113,7 @@ var DEFAULT_WORKERPALS_QUALITY_VALIDATION_STEP_TIMEOUT_MS = 180000;
|
|
|
114
113
|
var DEFAULT_WORKERPALS_QUALITY_CRITIC_TIMEOUT_MS = 45000;
|
|
115
114
|
var DEFAULT_WORKERPALS_QUALITY_CRITIC_MAX_DIFF_CHARS = 16000;
|
|
116
115
|
var DEFAULT_WORKERPALS_QUALITY_CRITIC_MAX_VALIDATION_OUTPUT_CHARS = 8000;
|
|
116
|
+
var DEFAULT_WORKERPALS_EXECUTOR = "openai_codex";
|
|
117
117
|
var DEFAULT_WORKERPALS_EXECUTOR_RESULT_PREFIX = "__PUSHPALS_OH_RESULT__ ";
|
|
118
118
|
var DEFAULT_REMOTEBUDDY_MEMORY_MAX_RECALL_ITEMS = 12;
|
|
119
119
|
var DEFAULT_REMOTEBUDDY_MEMORY_MAX_RECALL_CHARS = 2400;
|
|
@@ -155,6 +155,12 @@ function parseTomlFile(path) {
|
|
|
155
155
|
return {};
|
|
156
156
|
return parsed;
|
|
157
157
|
}
|
|
158
|
+
function parseRequiredTomlFile(path) {
|
|
159
|
+
if (!existsSync(path)) {
|
|
160
|
+
throw new Error(`Missing required runtime config file: ${path}`);
|
|
161
|
+
}
|
|
162
|
+
return parseTomlFile(path);
|
|
163
|
+
}
|
|
158
164
|
function isObject(value) {
|
|
159
165
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
160
166
|
}
|
|
@@ -260,20 +266,7 @@ function resolveRuntimeConfigDir(projectRoot, configuredDir) {
|
|
|
260
266
|
if (configuredDir && configuredDir.trim()) {
|
|
261
267
|
return resolvePathFromRoot(projectRoot, configuredDir);
|
|
262
268
|
}
|
|
263
|
-
|
|
264
|
-
const legacyDir = resolvePathFromRoot(projectRoot, LEGACY_CONFIG_DIR);
|
|
265
|
-
if (existsSync(join(canonicalDir, "default.toml")))
|
|
266
|
-
return canonicalDir;
|
|
267
|
-
if (existsSync(join(legacyDir, "default.toml")))
|
|
268
|
-
return legacyDir;
|
|
269
|
-
return canonicalDir;
|
|
270
|
-
}
|
|
271
|
-
function parseTomlWithLegacyFallback(primaryPath, fallbackPath) {
|
|
272
|
-
if (existsSync(primaryPath))
|
|
273
|
-
return parseTomlFile(primaryPath);
|
|
274
|
-
if (fallbackPath && existsSync(fallbackPath))
|
|
275
|
-
return parseTomlFile(fallbackPath);
|
|
276
|
-
return {};
|
|
269
|
+
return resolvePathFromRoot(projectRoot, DEFAULT_CONFIG_DIR);
|
|
277
270
|
}
|
|
278
271
|
function normalizeBackend(value) {
|
|
279
272
|
const text = value.trim().toLowerCase();
|
|
@@ -345,17 +338,15 @@ function loadPushPalsConfig(options = {}) {
|
|
|
345
338
|
const projectRoot = resolve(projectRootOverride);
|
|
346
339
|
const configDirOverride = firstNonEmpty(options.configDir, process.env.PUSHPALS_CONFIG_DIR_OVERRIDE, "");
|
|
347
340
|
const configDir = resolveRuntimeConfigDir(projectRoot, configDirOverride);
|
|
348
|
-
const legacyConfigDir = resolvePathFromRoot(projectRoot, LEGACY_CONFIG_DIR);
|
|
349
|
-
const fallbackConfigDir = !configDirOverride && configDir !== legacyConfigDir ? legacyConfigDir : "";
|
|
350
341
|
const cacheKey = `${projectRoot}::${configDir}::${process.env.PUSHPALS_PROFILE ?? ""}`;
|
|
351
342
|
if (!options.reload && cachedConfig && cachedConfigKey === cacheKey) {
|
|
352
343
|
return cachedConfig;
|
|
353
344
|
}
|
|
354
|
-
const defaultToml =
|
|
345
|
+
const defaultToml = parseRequiredTomlFile(join(configDir, "default.toml"));
|
|
355
346
|
const preferredProfile = firstNonEmpty(process.env.PUSHPALS_PROFILE, asString(defaultToml.profile, "dev"), "dev");
|
|
356
|
-
const profileToml =
|
|
357
|
-
const localExampleToml =
|
|
358
|
-
const localToml =
|
|
347
|
+
const profileToml = parseTomlFile(join(configDir, `${preferredProfile}.toml`));
|
|
348
|
+
const localExampleToml = parseTomlFile(join(configDir, "local.example.toml"));
|
|
349
|
+
const localToml = parseTomlFile(join(configDir, "local.toml"));
|
|
359
350
|
const merged = mergeDeep(mergeDeep(mergeDeep(defaultToml, profileToml), localExampleToml), localToml);
|
|
360
351
|
const profile = firstNonEmpty(process.env.PUSHPALS_PROFILE, asString(merged.profile, preferredProfile), preferredProfile);
|
|
361
352
|
const sessionId = firstNonEmpty(process.env.PUSHPALS_SESSION_ID, asString(merged.session_id, "dev"), "dev");
|
|
@@ -462,7 +453,7 @@ function loadPushPalsConfig(options = {}) {
|
|
|
462
453
|
const workerOpenHandsNode = getObject(workerNode, "openhands");
|
|
463
454
|
const workerPollMs = Math.max(200, asInt(parseIntEnv("WORKERPALS_POLL_MS") ?? workerNode.poll_ms, 2000));
|
|
464
455
|
const workerHeartbeatMs = Math.max(200, asInt(parseIntEnv("WORKERPALS_HEARTBEAT_MS") ?? workerNode.heartbeat_ms, 5000));
|
|
465
|
-
const workerExecutor = firstNonEmpty(process.env.WORKERPALS_EXECUTOR, asString(workerNode.executor,
|
|
456
|
+
const workerExecutor = firstNonEmpty(process.env.WORKERPALS_EXECUTOR, asString(workerNode.executor, DEFAULT_WORKERPALS_EXECUTOR), DEFAULT_WORKERPALS_EXECUTOR).toLowerCase();
|
|
466
457
|
const workerOpenHandsPython = firstNonEmpty(process.env.WORKERPALS_OPENHANDS_PYTHON, asString(workerNode.openhands_python, "python"), "python");
|
|
467
458
|
const workerOpenHandsTimeoutMs = Math.max(1e4, asInt(parseIntEnv("WORKERPALS_OPENHANDS_TIMEOUT_MS") ?? workerNode.openhands_timeout_ms, 1800000));
|
|
468
459
|
const workerMiniswePython = firstNonEmpty(process.env.WORKERPALS_MINISWE_PYTHON, asString(workerNode.miniswe_python, "python"), "python");
|
|
@@ -964,18 +955,10 @@ function resolveClientConfigDir(projectRoot, runtimeRoot, explicitConfigDir) {
|
|
|
964
955
|
if (runtimeHasConfigDir(runtimeRoot, "configs")) {
|
|
965
956
|
return runtimeCanonical;
|
|
966
957
|
}
|
|
967
|
-
const runtimeLegacy = resolve2(runtimeRoot, "config");
|
|
968
|
-
if (runtimeHasConfigDir(runtimeRoot, "config")) {
|
|
969
|
-
return runtimeLegacy;
|
|
970
|
-
}
|
|
971
958
|
const projectCanonical = resolve2(projectRoot, "configs");
|
|
972
959
|
if (runtimeHasConfigDir(projectRoot, "configs")) {
|
|
973
960
|
return projectCanonical;
|
|
974
961
|
}
|
|
975
|
-
const projectLegacy = resolve2(projectRoot, "config");
|
|
976
|
-
if (runtimeHasConfigDir(projectRoot, "config")) {
|
|
977
|
-
return projectLegacy;
|
|
978
|
-
}
|
|
979
962
|
return runtimeCanonical;
|
|
980
963
|
}
|
|
981
964
|
function toDisplayPath(currentRoot, pathValue) {
|
|
@@ -1025,8 +1008,7 @@ function evaluateClientRuntimePreflight(options) {
|
|
|
1025
1008
|
});
|
|
1026
1009
|
}
|
|
1027
1010
|
const localTomlPath = resolve2(runtimeRoot, "configs", "local.toml");
|
|
1028
|
-
|
|
1029
|
-
if (!existsSync2(localTomlPath) && !existsSync2(legacyLocalTomlPath)) {
|
|
1011
|
+
if (!existsSync2(localTomlPath)) {
|
|
1030
1012
|
const localExamplePath = resolve2(runtimeRoot, "configs", "local.example.toml");
|
|
1031
1013
|
issues.push({
|
|
1032
1014
|
code: "missing_local_toml",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { readFileSync } from "fs";
|
|
2
|
-
import {
|
|
3
|
-
import { loadPushPalsConfig } from "shared";
|
|
1
|
+
import { existsSync, readFileSync } from "fs";
|
|
2
|
+
import { join } from "path";
|
|
3
|
+
import { DEFAULT_WORKERPALS_EXECUTOR, loadPushPalsConfig } from "shared";
|
|
4
4
|
import type { ExecutorBackend } from "../common/types.js";
|
|
5
5
|
import { MINISWE_BACKEND } from "./miniswe_backend.js";
|
|
6
6
|
import { OPENAI_CODEX_BACKEND } from "./openai_codex_backend.js";
|
|
@@ -8,7 +8,7 @@ import { OPENHANDS_BACKEND } from "./openhands_backend.js";
|
|
|
8
8
|
import type { BackendTaskExecutor, DockerBackendSpec } from "./types.js";
|
|
9
9
|
import { registerBackendTaskExecutor } from "./task_execute_registry.js";
|
|
10
10
|
|
|
11
|
-
const FALLBACK_DEFAULT_EXECUTOR: ExecutorBackend =
|
|
11
|
+
const FALLBACK_DEFAULT_EXECUTOR: ExecutorBackend = DEFAULT_WORKERPALS_EXECUTOR;
|
|
12
12
|
|
|
13
13
|
interface BackendTomlShape {
|
|
14
14
|
default_backend?: string;
|
|
@@ -32,16 +32,25 @@ function toStrings(value: unknown): string[] {
|
|
|
32
32
|
.filter(Boolean);
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
function
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
return {};
|
|
35
|
+
export function parseRequiredBackendToml(path: string): BackendTomlShape {
|
|
36
|
+
if (!existsSync(path)) {
|
|
37
|
+
throw new Error(`Missing required runtime backend config file: ${path}`);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const parsed = Bun.TOML.parse(readFileSync(path, "utf-8")) as unknown;
|
|
41
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
42
|
+
throw new Error(`Invalid runtime backend config file: ${path}`);
|
|
44
43
|
}
|
|
44
|
+
return parsed as BackendTomlShape;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function resolveBackendTomlPath(configDir: string): string {
|
|
48
|
+
return join(configDir, "backend.toml");
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function loadBackendToml(): BackendTomlShape {
|
|
52
|
+
const path = resolveBackendTomlPath(loadPushPalsConfig().configDir);
|
|
53
|
+
return parseRequiredBackendToml(path);
|
|
45
54
|
}
|
|
46
55
|
|
|
47
56
|
const config = loadBackendToml();
|
|
@@ -58,7 +67,9 @@ export const DEFAULT_EXECUTOR = (
|
|
|
58
67
|
typeof config.default_backend === "string" &&
|
|
59
68
|
EXECUTOR_BACKENDS.includes(config.default_backend as ExecutorBackend)
|
|
60
69
|
? config.default_backend
|
|
61
|
-
: (
|
|
70
|
+
: EXECUTOR_BACKENDS.includes(FALLBACK_DEFAULT_EXECUTOR)
|
|
71
|
+
? FALLBACK_DEFAULT_EXECUTOR
|
|
72
|
+
: (EXECUTOR_BACKENDS[0] ?? FALLBACK_DEFAULT_EXECUTOR)
|
|
62
73
|
) as ExecutorBackend;
|
|
63
74
|
|
|
64
75
|
export const SHARED_DOCKER_PASSTHROUGH_ENV = toStrings(config.env?.shared_passthrough);
|
|
@@ -67,21 +67,11 @@ function resolveClientConfigDir(
|
|
|
67
67
|
return runtimeCanonical;
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
-
const runtimeLegacy = resolve(runtimeRoot, "config");
|
|
71
|
-
if (runtimeHasConfigDir(runtimeRoot, "config")) {
|
|
72
|
-
return runtimeLegacy;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
70
|
const projectCanonical = resolve(projectRoot, "configs");
|
|
76
71
|
if (runtimeHasConfigDir(projectRoot, "configs")) {
|
|
77
72
|
return projectCanonical;
|
|
78
73
|
}
|
|
79
74
|
|
|
80
|
-
const projectLegacy = resolve(projectRoot, "config");
|
|
81
|
-
if (runtimeHasConfigDir(projectRoot, "config")) {
|
|
82
|
-
return projectLegacy;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
75
|
return runtimeCanonical;
|
|
86
76
|
}
|
|
87
77
|
|
|
@@ -145,8 +135,7 @@ export function evaluateClientRuntimePreflight(
|
|
|
145
135
|
}
|
|
146
136
|
|
|
147
137
|
const localTomlPath = resolve(runtimeRoot, "configs", "local.toml");
|
|
148
|
-
|
|
149
|
-
if (!existsSync(localTomlPath) && !existsSync(legacyLocalTomlPath)) {
|
|
138
|
+
if (!existsSync(localTomlPath)) {
|
|
150
139
|
const localExamplePath = resolve(runtimeRoot, "configs", "local.example.toml");
|
|
151
140
|
issues.push({
|
|
152
141
|
code: "missing_local_toml",
|
|
@@ -10,7 +10,6 @@ interface TomlObject {
|
|
|
10
10
|
|
|
11
11
|
const PROJECT_ROOT = resolve(import.meta.dir, "..", "..", "..");
|
|
12
12
|
const DEFAULT_CONFIG_DIR = "configs";
|
|
13
|
-
const LEGACY_CONFIG_DIR = "config";
|
|
14
13
|
|
|
15
14
|
const TRUTHY = new Set(["1", "true", "yes", "on"]);
|
|
16
15
|
const FALSY = new Set(["0", "false", "no", "off"]);
|
|
@@ -24,6 +23,7 @@ const DEFAULT_WORKERPALS_QUALITY_VALIDATION_STEP_TIMEOUT_MS = 180_000;
|
|
|
24
23
|
const DEFAULT_WORKERPALS_QUALITY_CRITIC_TIMEOUT_MS = 45_000;
|
|
25
24
|
const DEFAULT_WORKERPALS_QUALITY_CRITIC_MAX_DIFF_CHARS = 16_000;
|
|
26
25
|
const DEFAULT_WORKERPALS_QUALITY_CRITIC_MAX_VALIDATION_OUTPUT_CHARS = 8_000;
|
|
26
|
+
export const DEFAULT_WORKERPALS_EXECUTOR = "openai_codex";
|
|
27
27
|
const DEFAULT_WORKERPALS_EXECUTOR_RESULT_PREFIX = "__PUSHPALS_OH_RESULT__ ";
|
|
28
28
|
const DEFAULT_REMOTEBUDDY_MEMORY_MAX_RECALL_ITEMS = 12;
|
|
29
29
|
const DEFAULT_REMOTEBUDDY_MEMORY_MAX_RECALL_CHARS = 2400;
|
|
@@ -320,6 +320,13 @@ function parseTomlFile(path: string): TomlObject {
|
|
|
320
320
|
return parsed as TomlObject;
|
|
321
321
|
}
|
|
322
322
|
|
|
323
|
+
function parseRequiredTomlFile(path: string): TomlObject {
|
|
324
|
+
if (!existsSync(path)) {
|
|
325
|
+
throw new Error(`Missing required runtime config file: ${path}`);
|
|
326
|
+
}
|
|
327
|
+
return parseTomlFile(path);
|
|
328
|
+
}
|
|
329
|
+
|
|
323
330
|
function isObject(value: unknown): value is TomlObject {
|
|
324
331
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
325
332
|
}
|
|
@@ -424,20 +431,7 @@ function resolveRuntimeConfigDir(projectRoot: string, configuredDir?: string): s
|
|
|
424
431
|
return resolvePathFromRoot(projectRoot, configuredDir);
|
|
425
432
|
}
|
|
426
433
|
|
|
427
|
-
|
|
428
|
-
const legacyDir = resolvePathFromRoot(projectRoot, LEGACY_CONFIG_DIR);
|
|
429
|
-
if (existsSync(join(canonicalDir, "default.toml"))) return canonicalDir;
|
|
430
|
-
if (existsSync(join(legacyDir, "default.toml"))) return legacyDir;
|
|
431
|
-
return canonicalDir;
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
function parseTomlWithLegacyFallback(
|
|
435
|
-
primaryPath: string,
|
|
436
|
-
fallbackPath?: string,
|
|
437
|
-
): TomlObject {
|
|
438
|
-
if (existsSync(primaryPath)) return parseTomlFile(primaryPath);
|
|
439
|
-
if (fallbackPath && existsSync(fallbackPath)) return parseTomlFile(fallbackPath);
|
|
440
|
-
return {};
|
|
434
|
+
return resolvePathFromRoot(projectRoot, DEFAULT_CONFIG_DIR);
|
|
441
435
|
}
|
|
442
436
|
|
|
443
437
|
function normalizeBackend(value: string): string {
|
|
@@ -570,35 +564,20 @@ export function loadPushPalsConfig(options: LoadOptions = {}): PushPalsConfig {
|
|
|
570
564
|
"",
|
|
571
565
|
);
|
|
572
566
|
const configDir = resolveRuntimeConfigDir(projectRoot, configDirOverride);
|
|
573
|
-
const legacyConfigDir = resolvePathFromRoot(projectRoot, LEGACY_CONFIG_DIR);
|
|
574
|
-
const fallbackConfigDir =
|
|
575
|
-
!configDirOverride && configDir !== legacyConfigDir ? legacyConfigDir : "";
|
|
576
567
|
const cacheKey = `${projectRoot}::${configDir}::${process.env.PUSHPALS_PROFILE ?? ""}`;
|
|
577
568
|
if (!options.reload && cachedConfig && cachedConfigKey === cacheKey) {
|
|
578
569
|
return cachedConfig;
|
|
579
570
|
}
|
|
580
571
|
|
|
581
|
-
const defaultToml =
|
|
582
|
-
join(configDir, "default.toml"),
|
|
583
|
-
fallbackConfigDir ? join(fallbackConfigDir, "default.toml") : undefined,
|
|
584
|
-
);
|
|
572
|
+
const defaultToml = parseRequiredTomlFile(join(configDir, "default.toml"));
|
|
585
573
|
const preferredProfile = firstNonEmpty(
|
|
586
574
|
process.env.PUSHPALS_PROFILE,
|
|
587
575
|
asString(defaultToml.profile, "dev"),
|
|
588
576
|
"dev",
|
|
589
577
|
);
|
|
590
|
-
const profileToml =
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
);
|
|
594
|
-
const localExampleToml = parseTomlWithLegacyFallback(
|
|
595
|
-
join(configDir, "local.example.toml"),
|
|
596
|
-
fallbackConfigDir ? join(fallbackConfigDir, "local.example.toml") : undefined,
|
|
597
|
-
);
|
|
598
|
-
const localToml = parseTomlWithLegacyFallback(
|
|
599
|
-
join(configDir, "local.toml"),
|
|
600
|
-
fallbackConfigDir ? join(fallbackConfigDir, "local.toml") : undefined,
|
|
601
|
-
);
|
|
578
|
+
const profileToml = parseTomlFile(join(configDir, `${preferredProfile}.toml`));
|
|
579
|
+
const localExampleToml = parseTomlFile(join(configDir, "local.example.toml"));
|
|
580
|
+
const localToml = parseTomlFile(join(configDir, "local.toml"));
|
|
602
581
|
const merged = mergeDeep(
|
|
603
582
|
mergeDeep(mergeDeep(defaultToml, profileToml), localExampleToml),
|
|
604
583
|
localToml,
|
|
@@ -889,8 +868,8 @@ export function loadPushPalsConfig(options: LoadOptions = {}): PushPalsConfig {
|
|
|
889
868
|
);
|
|
890
869
|
const workerExecutor = firstNonEmpty(
|
|
891
870
|
process.env.WORKERPALS_EXECUTOR,
|
|
892
|
-
asString(workerNode.executor,
|
|
893
|
-
|
|
871
|
+
asString(workerNode.executor, DEFAULT_WORKERPALS_EXECUTOR),
|
|
872
|
+
DEFAULT_WORKERPALS_EXECUTOR,
|
|
894
873
|
).toLowerCase();
|
|
895
874
|
const workerOpenHandsPython = firstNonEmpty(
|
|
896
875
|
process.env.WORKERPALS_OPENHANDS_PYTHON,
|
|
@@ -14,7 +14,6 @@ export type LocalBuddyRuntimeSnapshot = {
|
|
|
14
14
|
export const DEFAULT_LOCALBUDDY_PORT = 3003;
|
|
15
15
|
|
|
16
16
|
const DEFAULT_CONFIG_DIR = "configs";
|
|
17
|
-
const LEGACY_CONFIG_DIR = "config";
|
|
18
17
|
const TRUTHY = new Set(["1", "true", "yes", "on"]);
|
|
19
18
|
const FALSY = new Set(["0", "false", "no", "off"]);
|
|
20
19
|
|
|
@@ -71,27 +70,11 @@ export function loadLocalBuddyRuntimeSnapshotFromFiles(
|
|
|
71
70
|
|
|
72
71
|
const configDirOverride = firstNonEmpty(mergedEnv.PUSHPALS_CONFIG_DIR_OVERRIDE);
|
|
73
72
|
const configDir = resolveRuntimeConfigDir(workspaceRoot, configDirOverride);
|
|
74
|
-
const
|
|
75
|
-
const fallbackConfigDir =
|
|
76
|
-
!configDirOverride && configDir !== legacyConfigDir ? legacyConfigDir : "";
|
|
77
|
-
|
|
78
|
-
const defaultToml = readTomlSliceWithFallback(
|
|
79
|
-
join(configDir, "default.toml"),
|
|
80
|
-
fallbackConfigDir ? join(fallbackConfigDir, "default.toml") : undefined,
|
|
81
|
-
);
|
|
73
|
+
const defaultToml = readRequiredTomlSlice(join(configDir, "default.toml"));
|
|
82
74
|
const preferredProfile = firstNonEmpty(mergedEnv.PUSHPALS_PROFILE, defaultToml.profile, "dev");
|
|
83
|
-
const profileToml =
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
);
|
|
87
|
-
const localExampleToml = readTomlSliceWithFallback(
|
|
88
|
-
join(configDir, "local.example.toml"),
|
|
89
|
-
fallbackConfigDir ? join(fallbackConfigDir, "local.example.toml") : undefined,
|
|
90
|
-
);
|
|
91
|
-
const localToml = readTomlSliceWithFallback(
|
|
92
|
-
join(configDir, "local.toml"),
|
|
93
|
-
fallbackConfigDir ? join(fallbackConfigDir, "local.toml") : undefined,
|
|
94
|
-
);
|
|
75
|
+
const profileToml = readTomlSlice(join(configDir, `${preferredProfile}.toml`));
|
|
76
|
+
const localExampleToml = readTomlSlice(join(configDir, "local.example.toml"));
|
|
77
|
+
const localToml = readTomlSlice(join(configDir, "local.toml"));
|
|
95
78
|
|
|
96
79
|
const mergedLocalbuddy = {
|
|
97
80
|
...defaultToml.localbuddy,
|
|
@@ -168,11 +151,7 @@ function resolveRuntimeConfigDir(workspaceRoot: string, configuredDir?: string):
|
|
|
168
151
|
return resolvePathFromRoot(workspaceRoot, configuredDir);
|
|
169
152
|
}
|
|
170
153
|
|
|
171
|
-
|
|
172
|
-
const legacyDir = resolvePathFromRoot(workspaceRoot, LEGACY_CONFIG_DIR);
|
|
173
|
-
if (existsSync(join(canonicalDir, "default.toml"))) return canonicalDir;
|
|
174
|
-
if (existsSync(join(legacyDir, "default.toml"))) return legacyDir;
|
|
175
|
-
return canonicalDir;
|
|
154
|
+
return resolvePathFromRoot(workspaceRoot, DEFAULT_CONFIG_DIR);
|
|
176
155
|
}
|
|
177
156
|
|
|
178
157
|
function parseBoolEnv(value: string | undefined): boolean | undefined {
|
|
@@ -190,12 +169,18 @@ function parseIntEnv(value: string | undefined): number | undefined {
|
|
|
190
169
|
return Number.isFinite(parsed) ? parsed : undefined;
|
|
191
170
|
}
|
|
192
171
|
|
|
193
|
-
function
|
|
194
|
-
if (existsSync(
|
|
195
|
-
if (fallbackPath && existsSync(fallbackPath)) return parseTomlSlice(fallbackPath);
|
|
172
|
+
function readTomlSlice(path: string): LocalBuddyTomlSlice {
|
|
173
|
+
if (existsSync(path)) return parseTomlSlice(path);
|
|
196
174
|
return {};
|
|
197
175
|
}
|
|
198
176
|
|
|
177
|
+
function readRequiredTomlSlice(path: string): LocalBuddyTomlSlice {
|
|
178
|
+
if (!existsSync(path)) {
|
|
179
|
+
throw new Error(`Missing required runtime config file: ${path}`);
|
|
180
|
+
}
|
|
181
|
+
return parseTomlSlice(path);
|
|
182
|
+
}
|
|
183
|
+
|
|
199
184
|
function parseTomlSlice(path: string): LocalBuddyTomlSlice {
|
|
200
185
|
const text = readFileSync(path, "utf8");
|
|
201
186
|
const result: LocalBuddyTomlSlice = {};
|