stim 1.8.0 → 1.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +23 -155
- package/dist/{android-BRgBYzU0.mjs → android-BPGizezh.mjs} +112 -135
- package/dist/{android-DeYdjjBP.mjs → android-DEgo4oCo.mjs} +2 -2
- package/dist/{android-DWssqHQ8.mjs → android-_y4Ohi5z.mjs} +54 -15
- package/dist/android-cas-compiler.mjs +2 -2
- package/dist/{android-cas-SWIjzeuL.mjs → android-cas-eiExNLf7.mjs} +21 -14
- package/dist/app-install-Uf3a83Tv.mjs +819 -0
- package/dist/{build-lock-CgtsB6TV.mjs → build-lock-DPXPLgTc.mjs} +120 -24
- package/dist/build-progress-CVqkfPC6.mjs +188 -0
- package/dist/{cache-manifest-CYJi8-Hx.mjs → cache-manifest-Dg7OnMrp.mjs} +4 -4
- package/dist/cache-manifest.mjs +1 -1
- package/dist/cli.mjs +22 -19
- package/dist/collector-run.d.mts +2 -0
- package/dist/collector-run.mjs +10 -9
- package/dist/{command-output-B3ycpsYv.mjs → command-output-gByVmIjy.mjs} +11 -2
- package/dist/{config-B7iyKWkL.mjs → config-Cp9lM3wX.mjs} +187 -57
- package/dist/{dependency-state-D0M7oKA7.mjs → dependency-state-Bq5DcLGn.mjs} +2 -2
- package/dist/{deps-oCXVNEqQ.mjs → deps-Cip5vUm1.mjs} +8 -5
- package/dist/{detached-entry-Bpo6ZY_I.mjs → detached-entry-KEu0_AXL.mjs} +1 -1
- package/dist/{device-BUoZyMoR.mjs → dev-client-HyqISM0h.mjs} +1178 -635
- package/dist/{device-RdujjHLB.mjs → device-D4U-xLty.mjs} +13 -20
- package/dist/{device-lease-Ffz_M5t0.mjs → device-lease-Crs-HkJY.mjs} +16 -9
- package/dist/{device-pool-BxRwdufO.mjs → device-pool-CnTAz8X1.mjs} +7 -7
- package/dist/{device-remote-ByN8P6CB.mjs → device-remote-AQ5rQPqr.mjs} +482 -35
- package/dist/{doctor-BMt156qe.mjs → doctor-B_Ei3bZu.mjs} +95 -107
- package/dist/{error-diagnostics-D1Kaf-eT.mjs → error-diagnostics-Vfz83GCF.mjs} +22 -16
- package/dist/exec-jIAlgilk.mjs +132 -0
- package/dist/{gc-v2YcoJvm.mjs → gc-Ckw8RQHi.mjs} +763 -126
- package/dist/{guide-BTAlD1_y.mjs → guide-BiAbhs1J.mjs} +891 -501
- package/dist/{guide-status-Craq9z0t.mjs → guide-status-BAMVU0ZA.mjs} +5 -3
- package/dist/{ios-BcCiI4TS.mjs → ios-BL2NFckr.mjs} +43 -20
- package/dist/{ios-BP04pY5f.mjs → ios-BzUJWk1K.mjs} +141 -175
- package/dist/{ios-device-CauFJiYx.mjs → ios-device-D972i9wf.mjs} +149 -52
- package/dist/{ios-device-CFXA46ez.mjs → ios-device-DPsSm0v_.mjs} +3 -2
- package/dist/launch-verify-Q_OtW1Rf.mjs +365 -0
- package/dist/{logs-CakdBTtm.mjs → logs-CI9NQSK7.mjs} +18 -13
- package/dist/{logs-query-BGL-Pl12.mjs → logs-query-Cqma3WIu.mjs} +36 -28
- package/dist/{metro-C7bcJ0uo.mjs → metro-DrLHaMn2.mjs} +78 -8
- package/dist/{named-ports-DzMOlmaX.mjs → named-ports-CmLQSIRj.mjs} +4 -4
- package/dist/{ndjson-BZwI1NBv.mjs → ndjson-9uFNRwfe.mjs} +36 -3
- package/dist/{ownership-Cp52QAK1.mjs → ownership-D15Op8vN.mjs} +3 -3
- package/dist/{ownership-wolE-0Do.mjs → ownership-DCQPuWEc.mjs} +26 -7
- package/dist/{ports-BIbJaKNW.mjs → ports-BNKoWVWZ.mjs} +3 -3
- package/dist/{process-output-Dl5uKE03.mjs → process-output-Fpl8PYi8.mjs} +1 -1
- package/dist/{project-DDZWf_16.mjs → project-DS112DYB.mjs} +8 -3
- package/dist/{reload-BdypPbjM.mjs → reload-ZNJUo1pl.mjs} +12 -13
- package/dist/{server-bare-BQkyxa_b.mjs → server-bare-DWkkcIxV.mjs} +2 -2
- package/dist/{server-expo-BVAA1OqJ.mjs → server-expo-B_lctBR3.mjs} +8 -7
- package/dist/server-expo-CeILEu86.mjs +2 -0
- package/dist/settings-BKNh5rl4.mjs +376 -0
- package/dist/{settings-BXXorVM2.mjs → settings-D030k0t4.mjs} +464 -152
- package/dist/settings.schema.json +989 -0
- package/dist/{teardown-BJqEzPo_.mjs → sim-pool-KaIsp2Ft.mjs} +14 -419
- package/dist/simslim-B_LsGLuJ.mjs +259 -0
- package/dist/{slot-launch-ZUUe0TQP.mjs → slot-launch-DU9A-gYw.mjs} +4 -4
- package/dist/spawn-claims-Dn3C_N6w.mjs +49 -0
- package/dist/{start-CmxtOKjU.mjs → start-DYkkKF0s.mjs} +27 -31
- package/dist/{state-DZobzxLW.mjs → state-NcJzMEBF.mjs} +5 -3
- package/dist/{stats-CLg5RuDS.mjs → stats-B63-JVAY.mjs} +4 -4
- package/dist/{stats-BYcZ6n1h.mjs → stats-DG9e66Rz.mjs} +66 -5
- package/dist/status-S6ehL4Ui.mjs +932 -0
- package/dist/{stop-C8JW6kKp.mjs → stop-BO28HGqF.mjs} +101 -25
- package/dist/{stop-B1kOpYei.mjs → stop-T1R-cZRz.mjs} +2 -2
- package/dist/supervisor-run.mjs +52 -34
- package/dist/{workspace-process-lock-BYfZz_S-.mjs → workspace-process-lock-DWaiRD0e.mjs} +14 -9
- package/dist/{workspace-state-BT5E3SA2.mjs → workspace-state-DF2gCFhx.mjs} +52 -29
- package/dist/worktree-DKhSF0UX.mjs +2 -0
- package/dist/{worktree-CFLA-6MX.mjs → worktree-LGB-UwgG.mjs} +603 -59
- package/dist/{worktree-FG_ZKKdb.mjs → worktree-R_cUlE7s.mjs} +62 -41
- package/dist/{xcode-B6YaWeg0.mjs → xcode-BZqyxh3e.mjs} +216 -58
- package/package.json +5 -6
- package/skill/SKILL.md +2 -0
- package/dist/app-install-BDbsSgCl.mjs +0 -1175
- package/dist/build-slots-C-oAHRT1.mjs +0 -151
- package/dist/dev-client-BmT-ioFI.mjs +0 -797
- package/dist/exec-B29XNuhP.mjs +0 -77
- package/dist/reclaim-KJ-0uWEF.mjs +0 -361
- package/dist/server-expo-YDDG3eP7.mjs +0 -2
- package/dist/status-DdkLki47.mjs +0 -426
- package/dist/{metro-store-CDDZHtPl.mjs → metro-store-DzeWkfqW.mjs} +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { t as withWorkspaceProcessLock } from "./workspace-process-lock-
|
|
1
|
+
import { D as process_identity_exports, T as withConfigLock, f as getProject, g as loadConfig, s as ensureConfig, u as getConfigDir, x as saveConfig } from "./config-Cp9lM3wX.mjs";
|
|
2
|
+
import { t as getExecutor } from "./exec-jIAlgilk.mjs";
|
|
3
|
+
import { d as isPortFree, l as signalProcessTree, r as listeningPids } from "./metro-DrLHaMn2.mjs";
|
|
4
|
+
import { t as withWorkspaceProcessLock } from "./workspace-process-lock-DWaiRD0e.mjs";
|
|
5
5
|
import { realpathSync } from "node:fs";
|
|
6
6
|
//#region src/named-ports.ts
|
|
7
7
|
const FIRST_PORT = 8900;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import { closeSync, mkdirSync, openSync, writeSync } from "fs";
|
|
1
|
+
import { closeSync, mkdirSync, openSync, readFileSync, writeSync } from "fs";
|
|
2
2
|
import { dirname } from "path";
|
|
3
|
+
import { rotateLog, rotatedLogPath } from "@stim-cli/core";
|
|
3
4
|
//#region src/ndjson.ts
|
|
5
|
+
const ROTATE_CHECK_MS = 1e3;
|
|
4
6
|
const LEVELS = [
|
|
5
7
|
"debug",
|
|
6
8
|
"info",
|
|
@@ -42,6 +44,19 @@ function parseNdjsonText(text) {
|
|
|
42
44
|
}
|
|
43
45
|
return out;
|
|
44
46
|
}
|
|
47
|
+
function readNdjsonGenerations(file) {
|
|
48
|
+
const out = [];
|
|
49
|
+
for (const path of [rotatedLogPath(file), file]) {
|
|
50
|
+
let text;
|
|
51
|
+
try {
|
|
52
|
+
text = readFileSync(path, "utf-8");
|
|
53
|
+
} catch {
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
for (const record of parseNdjsonText(text)) out.push(record);
|
|
57
|
+
}
|
|
58
|
+
return out;
|
|
59
|
+
}
|
|
45
60
|
function formatNdjsonLine(record) {
|
|
46
61
|
try {
|
|
47
62
|
return `${JSON.stringify(record)}\n`;
|
|
@@ -49,9 +64,11 @@ function formatNdjsonLine(record) {
|
|
|
49
64
|
return null;
|
|
50
65
|
}
|
|
51
66
|
}
|
|
52
|
-
function createNdjsonWriter(file, { truncate = false, fields = {} } = {}) {
|
|
67
|
+
function createNdjsonWriter(file, { truncate = false, fields = {}, maxBytes, now = Date.now } = {}) {
|
|
53
68
|
let fd = null;
|
|
54
69
|
let freshFile = truncate;
|
|
70
|
+
let uncheckedBytes = 0;
|
|
71
|
+
let checkedAt = 0;
|
|
55
72
|
let written = 0;
|
|
56
73
|
let dropped = 0;
|
|
57
74
|
let lastError = null;
|
|
@@ -61,6 +78,20 @@ function createNdjsonWriter(file, { truncate = false, fields = {} } = {}) {
|
|
|
61
78
|
fd = openSync(file, freshFile ? "w" : "a");
|
|
62
79
|
freshFile = false;
|
|
63
80
|
}
|
|
81
|
+
function rotateIfDue(limit) {
|
|
82
|
+
if (fd !== null && uncheckedBytes < limit / 8 && now() - checkedAt < ROTATE_CHECK_MS) return;
|
|
83
|
+
if (fd !== null) {
|
|
84
|
+
try {
|
|
85
|
+
closeSync(fd);
|
|
86
|
+
} catch {}
|
|
87
|
+
fd = null;
|
|
88
|
+
}
|
|
89
|
+
uncheckedBytes = 0;
|
|
90
|
+
checkedAt = now();
|
|
91
|
+
try {
|
|
92
|
+
rotateLog(file, limit);
|
|
93
|
+
} catch {}
|
|
94
|
+
}
|
|
64
95
|
function write(record) {
|
|
65
96
|
if (closed) {
|
|
66
97
|
dropped += 1;
|
|
@@ -76,8 +107,10 @@ function createNdjsonWriter(file, { truncate = false, fields = {} } = {}) {
|
|
|
76
107
|
return false;
|
|
77
108
|
}
|
|
78
109
|
try {
|
|
110
|
+
if (maxBytes !== void 0) rotateIfDue(maxBytes);
|
|
79
111
|
if (fd === null) open();
|
|
80
112
|
writeSync(fd, line);
|
|
113
|
+
uncheckedBytes += Buffer.byteLength(line);
|
|
81
114
|
written += 1;
|
|
82
115
|
return true;
|
|
83
116
|
} catch (err) {
|
|
@@ -131,4 +164,4 @@ function stamp(record) {
|
|
|
131
164
|
};
|
|
132
165
|
}
|
|
133
166
|
//#endregion
|
|
134
|
-
export { parseNdjsonLine as a, levelRank as i, SOURCES as n,
|
|
167
|
+
export { parseNdjsonLine as a, levelRank as i, SOURCES as n, readNdjsonGenerations as o, createNdjsonWriter as r, LEVELS as t };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { D as process_identity_exports } from "./config-Cp9lM3wX.mjs";
|
|
2
|
+
import { c as writeWorkspaceState, o as withWorkspaceStateLock, r as readWorkspaceState } from "./workspace-state-DF2gCFhx.mjs";
|
|
3
|
+
import { a as pidExists } from "./metro-DrLHaMn2.mjs";
|
|
4
4
|
import { realpathSync } from "node:fs";
|
|
5
5
|
//#region src/collector/state.ts
|
|
6
6
|
function collectorRoot(root) {
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { t as createLineReader } from "./process-output-
|
|
4
|
-
import {
|
|
5
|
-
import { t as withWorkspaceProcessLock } from "./workspace-process-lock-
|
|
1
|
+
import { D as process_identity_exports, k as ownership_claim_exports, u as getConfigDir } from "./config-Cp9lM3wX.mjs";
|
|
2
|
+
import { t as getExecutor } from "./exec-jIAlgilk.mjs";
|
|
3
|
+
import { t as createLineReader } from "./process-output-Fpl8PYi8.mjs";
|
|
4
|
+
import { a as pidExists, l as signalProcessTree } from "./metro-DrLHaMn2.mjs";
|
|
5
|
+
import { r as workspaceProcessLockPath, t as withWorkspaceProcessLock } from "./workspace-process-lock-DWaiRD0e.mjs";
|
|
6
6
|
import { t as probePublicHttp } from "./public-http-probe-CyMDrQ3c.mjs";
|
|
7
7
|
import { closeSync, mkdirSync, openSync, readFileSync, unlinkSync } from "node:fs";
|
|
8
|
-
import { createHash, randomUUID } from "node:crypto";
|
|
9
8
|
import { basename, join, resolve, sep } from "node:path";
|
|
9
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
10
10
|
//#region src/engine/tunnel.ts
|
|
11
11
|
function tunnelArgv(provider, port, ngrokUrl, logFile) {
|
|
12
12
|
if (provider === "cloudflared") return {
|
|
@@ -78,6 +78,25 @@ async function withManagedRemoteWorktreeRemovalLock(worktreeRoot, fn, options =
|
|
|
78
78
|
ownerPurpose: "worktree removal"
|
|
79
79
|
});
|
|
80
80
|
}
|
|
81
|
+
function managedLockHolders(root) {
|
|
82
|
+
const locks = [{
|
|
83
|
+
label: "managed tunnel",
|
|
84
|
+
path: workspaceProcessLockPath(managedTunnelLockRoot(root), "metro-tunnel", false)
|
|
85
|
+
}, {
|
|
86
|
+
label: "managed remote",
|
|
87
|
+
path: workspaceProcessLockPath(managedRemoteWorktreeLockRoot(root), "managed-remote", true)
|
|
88
|
+
}];
|
|
89
|
+
const reasons = [];
|
|
90
|
+
for (const { label, path } of locks) {
|
|
91
|
+
const claims = (0, ownership_claim_exports.readClaimSet)(path);
|
|
92
|
+
const holder = claims.live[0];
|
|
93
|
+
if (holder) {
|
|
94
|
+
const purpose = typeof holder.details.purpose === "string" ? ` for ${holder.details.purpose}` : "";
|
|
95
|
+
reasons.push(`the ${label} lock is held${purpose}`);
|
|
96
|
+
} else if (claims.unresolved[0]) reasons.push(`the ${label} lock cannot be resolved: ${claims.unresolved[0].reason}`);
|
|
97
|
+
}
|
|
98
|
+
return reasons;
|
|
99
|
+
}
|
|
81
100
|
function managedTunnelLockRoot(root) {
|
|
82
101
|
const key = createHash("sha256").update(resolve(root)).digest("hex");
|
|
83
102
|
return join(getConfigDir(), "process-locks", key);
|
|
@@ -467,4 +486,4 @@ function numberOrNull(v) {
|
|
|
467
486
|
return typeof v === "number" && Number.isSafeInteger(v) && v > 0 ? v : null;
|
|
468
487
|
}
|
|
469
488
|
//#endregion
|
|
470
|
-
export {
|
|
489
|
+
export { terminateChild as a, withManagedTunnelLock as c, stopTunnel as i, withManagedTunnelRemovalLock as l, managedLockHolders as n, withManagedRemoteWorktreeLock as o, startTunnelSequence as r, withManagedRemoteWorktreeRemovalLock as s, resolveSupervisorTarget as t };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { f as getProject } from "./config-
|
|
2
|
-
import {
|
|
3
|
-
import { n as getNamedPort, t as clearNamedPorts } from "./named-ports-
|
|
1
|
+
import { f as getProject } from "./config-Cp9lM3wX.mjs";
|
|
2
|
+
import { o as findProjectRoot } from "./project-DS112DYB.mjs";
|
|
3
|
+
import { n as getNamedPort, t as clearNamedPorts } from "./named-ports-CmLQSIRj.mjs";
|
|
4
4
|
//#region src/commands/ports.ts
|
|
5
5
|
async function inProject(action) {
|
|
6
6
|
try {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { c as findEnclosingWorktreeRoot, f as getProject } from "./config-
|
|
2
|
-
import {
|
|
1
|
+
import { c as findEnclosingWorktreeRoot, f as getProject } from "./config-Cp9lM3wX.mjs";
|
|
2
|
+
import { _ as repoRoot } from "./worktree-R_cUlE7s.mjs";
|
|
3
3
|
import { existsSync, readFileSync, readdirSync, realpathSync } from "fs";
|
|
4
4
|
import { basename, dirname, join, resolve } from "path";
|
|
5
5
|
import { createRequire } from "module";
|
|
@@ -38,6 +38,11 @@ function ownedDeviceLabel(projectPath) {
|
|
|
38
38
|
const worktreeLabel = basename(realpathSync(root));
|
|
39
39
|
return worktreeLabel === appLabel ? appLabel : `${worktreeLabel}-${appLabel}`;
|
|
40
40
|
}
|
|
41
|
+
const NO_PROJECT_REFUSAL = {
|
|
42
|
+
code: "STIM_NO_PROJECT",
|
|
43
|
+
message: "Not in a React Native project (no package.json found).",
|
|
44
|
+
remedy: "Run this from the app directory -- the one holding package.json."
|
|
45
|
+
};
|
|
41
46
|
function findProjectRoot(startDir) {
|
|
42
47
|
let dir;
|
|
43
48
|
try {
|
|
@@ -240,4 +245,4 @@ function detectAndroidPackageFromGradle(projectRoot) {
|
|
|
240
245
|
return null;
|
|
241
246
|
}
|
|
242
247
|
//#endregion
|
|
243
|
-
export {
|
|
248
|
+
export { detectIsExpo as a, ownedDeviceLabel as c, detectBundleId as i, projectShortcut as l, appProjectProblem as n, findProjectRoot as o, detectAndroidPackage as r, isPackageResolvable as s, NO_PROJECT_REFUSAL as t, resolvePackageJson as u };
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
1
|
+
import { U as deviceSlotPlatforms, W as parseDeviceSlotKey, f as getProject } from "./config-Cp9lM3wX.mjs";
|
|
2
|
+
import { i as recordWorkspaceUse } from "./workspace-state-DF2gCFhx.mjs";
|
|
3
|
+
import { o as findProjectRoot } from "./project-DS112DYB.mjs";
|
|
4
|
+
import { d as readWorkspaceLaunches } from "./state-NcJzMEBF.mjs";
|
|
5
|
+
import { c as resolveProjectMetro } from "./metro-DrLHaMn2.mjs";
|
|
6
|
+
import { R as resolveOwnedAvdSerial } from "./android-_y4Ohi5z.mjs";
|
|
7
|
+
import { f as refuseNoProject, l as phaseLine } from "./command-output-gByVmIjy.mjs";
|
|
8
|
+
import { h as iosAppProcess, o as androidAppProcess } from "./app-install-Uf3a83Tv.mjs";
|
|
9
|
+
import { C as resolveOwnedIosSim } from "./ios-BL2NFckr.mjs";
|
|
10
|
+
import { n as nativeRunCommand } from "./slot-launch-DU9A-gYw.mjs";
|
|
10
11
|
import chalk from "chalk";
|
|
11
12
|
import { WebSocket } from "ws";
|
|
12
13
|
//#region src/engine/reload.ts
|
|
@@ -305,12 +306,10 @@ function registerReload(program, deps = {}) {
|
|
|
305
306
|
}
|
|
306
307
|
const root = (deps.findProjectRoot ?? DEFAULT_DEPS.findProjectRoot)(process.cwd());
|
|
307
308
|
if (!root) {
|
|
308
|
-
|
|
309
|
-
if (opts.json) console.log(JSON.stringify(error));
|
|
310
|
-
else console.error(chalk.red(phaseLine("error", `${error.code}: ${error.message}`)));
|
|
311
|
-
process.exitCode = 1;
|
|
309
|
+
refuseNoProject({ json: Boolean(opts.json) });
|
|
312
310
|
return;
|
|
313
311
|
}
|
|
312
|
+
recordWorkspaceUse(root);
|
|
314
313
|
const result = await runReload({
|
|
315
314
|
root,
|
|
316
315
|
platform: value ?? null,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { i as __require, t as __commonJSMin } from "./rolldown-runtime-BsOwBuO_.mjs";
|
|
2
2
|
import { n as supervisorError } from "./errors-B6W7FkxQ.mjs";
|
|
3
|
-
import {
|
|
4
|
-
import { a as metroStoreRoot, o as registerMetroStore, t as appendCacheStore } from "./metro-store-
|
|
3
|
+
import { S as projectMetroSharedCache } from "./settings-D030k0t4.mjs";
|
|
4
|
+
import { a as metroStoreRoot, o as registerMetroStore, t as appendCacheStore } from "./metro-store-DzeWkfqW.mjs";
|
|
5
5
|
import { createRequire } from "node:module";
|
|
6
6
|
import { isAbsolute, join, relative, sep } from "node:path";
|
|
7
7
|
//#endregion
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import { t as getExecutor } from "./exec-
|
|
2
|
-
import { r as createNdjsonWriter } from "./ndjson-
|
|
3
|
-
import {
|
|
1
|
+
import { t as getExecutor } from "./exec-jIAlgilk.mjs";
|
|
2
|
+
import { r as createNdjsonWriter } from "./ndjson-9uFNRwfe.mjs";
|
|
3
|
+
import { u as resolvePackageJson } from "./project-DS112DYB.mjs";
|
|
4
4
|
import { n as supervisorError } from "./errors-B6W7FkxQ.mjs";
|
|
5
|
-
import { n as stripAnsi, t as createLineReader } from "./process-output-
|
|
6
|
-
import {
|
|
7
|
-
import { a as metroStoreRoot, i as metroStoreConfirmedRoot, n as expoMetroConfigPath, o as registerMetroStore, r as expoMetroStoreEnv } from "./metro-store-
|
|
5
|
+
import { n as stripAnsi, t as createLineReader } from "./process-output-Fpl8PYi8.mjs";
|
|
6
|
+
import { S as projectMetroSharedCache } from "./settings-D030k0t4.mjs";
|
|
7
|
+
import { a as metroStoreRoot, i as metroStoreConfirmedRoot, n as expoMetroConfigPath, o as registerMetroStore, r as expoMetroStoreEnv } from "./metro-store-DzeWkfqW.mjs";
|
|
8
8
|
import { accessSync, constants, existsSync, readFileSync } from "node:fs";
|
|
9
|
+
import { LOG_ROTATE_BYTES } from "@stim-cli/core";
|
|
9
10
|
import { dirname, join, parse } from "node:path";
|
|
10
11
|
//#region src/supervisor/server-expo.ts
|
|
11
12
|
function delay(ms) {
|
|
@@ -209,7 +210,7 @@ async function startExpoServer({ root, port, logsDir, writer = null, spawnFn = n
|
|
|
209
210
|
throw supervisorError("STIM_EXPO_BIN", refusal.message, refusal.remedy);
|
|
210
211
|
}
|
|
211
212
|
const bin = resolved.path;
|
|
212
|
-
const log = writer || createNdjsonWriter(join(logsDir, "metro.ndjson"));
|
|
213
|
+
const log = writer || createNdjsonWriter(join(logsDir, "metro.ndjson"), { maxBytes: LOG_ROTATE_BYTES });
|
|
213
214
|
const spawn = spawnFn || ((cmd, args, opts) => getExecutor().spawn(cmd, args, opts));
|
|
214
215
|
const args = [
|
|
215
216
|
"start",
|
|
@@ -0,0 +1,376 @@
|
|
|
1
|
+
import { E as writeConfigSetting, T as withConfigLock, d as getConfigPath, g as loadConfig, j as isJsonObject, m as getRepoSettings, p as getProjectSettings } from "./config-Cp9lM3wX.mjs";
|
|
2
|
+
import { _ as repoRoot, s as gitCommonDir } from "./worktree-R_cUlE7s.mjs";
|
|
3
|
+
import { o as findProjectRoot, t as NO_PROJECT_REFUSAL } from "./project-DS112DYB.mjs";
|
|
4
|
+
import { B as isSensitiveReference, F as unknownSettingKeys, H as settingValueError, R as SETTINGS, T as readCommittedSettings, V as settingDefinition, z as SETTING_SCOPES } from "./settings-D030k0t4.mjs";
|
|
5
|
+
import { existsSync, readFileSync, renameSync, unlinkSync, writeFileSync } from "node:fs";
|
|
6
|
+
import { join } from "node:path";
|
|
7
|
+
import chalk from "chalk";
|
|
8
|
+
//#region src/commands/settings.ts
|
|
9
|
+
const MASK = "********";
|
|
10
|
+
const PRECEDENCE = [
|
|
11
|
+
"workspace",
|
|
12
|
+
"repo",
|
|
13
|
+
"committed",
|
|
14
|
+
"machine"
|
|
15
|
+
];
|
|
16
|
+
var Refusal = class extends Error {
|
|
17
|
+
code;
|
|
18
|
+
remedy;
|
|
19
|
+
constructor(code, message, remedy) {
|
|
20
|
+
super(message);
|
|
21
|
+
this.code = code;
|
|
22
|
+
this.remedy = remedy;
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
function readContext(env) {
|
|
26
|
+
const projectPath = findProjectRoot(process.cwd());
|
|
27
|
+
const start = projectPath ?? process.cwd();
|
|
28
|
+
const common = gitCommonDir(start);
|
|
29
|
+
return {
|
|
30
|
+
projectPath,
|
|
31
|
+
gitCommonDir: common,
|
|
32
|
+
repoRoot: common ? repoRoot(start) ?? projectPath : null,
|
|
33
|
+
machine: loadConfig(),
|
|
34
|
+
env
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
function valueAt(settings, key) {
|
|
38
|
+
let node = settings;
|
|
39
|
+
for (const segment of key.split(".")) {
|
|
40
|
+
if (!isJsonObject(node)) return void 0;
|
|
41
|
+
node = node[segment];
|
|
42
|
+
}
|
|
43
|
+
return node;
|
|
44
|
+
}
|
|
45
|
+
function committedDirectory(context, setting) {
|
|
46
|
+
return setting?.committedAt === "repository" ? repositoryDirectory(context) : appDirectory(context);
|
|
47
|
+
}
|
|
48
|
+
function repositoryDirectory(context) {
|
|
49
|
+
return context.repoRoot ?? context.projectPath;
|
|
50
|
+
}
|
|
51
|
+
function appDirectory(context) {
|
|
52
|
+
return context.projectPath ?? context.repoRoot;
|
|
53
|
+
}
|
|
54
|
+
function layerFile(context, scope, setting) {
|
|
55
|
+
const machineFile = getConfigPath();
|
|
56
|
+
if (scope === "machine") return machineFile;
|
|
57
|
+
if (scope === "workspace") return context.projectPath ? `${machineFile} (projects["${context.projectPath}"].settings)` : null;
|
|
58
|
+
if (scope === "repo") return context.gitCommonDir ? `${machineFile} (repos["${context.gitCommonDir}"].settings)` : null;
|
|
59
|
+
const directory = committedDirectory(context, setting);
|
|
60
|
+
return directory ? join(directory, ".stim.json") : null;
|
|
61
|
+
}
|
|
62
|
+
function layerSettings(context, scope, setting) {
|
|
63
|
+
if (scope === "machine") return context.machine ?? {};
|
|
64
|
+
if (scope === "workspace") return context.projectPath ? getProjectSettings(context.projectPath) : {};
|
|
65
|
+
if (scope === "repo") return context.gitCommonDir ? getRepoSettings(context.gitCommonDir) : {};
|
|
66
|
+
return readCommittedSettings(committedDirectory(context, setting));
|
|
67
|
+
}
|
|
68
|
+
function masked(setting, value) {
|
|
69
|
+
return setting.sensitive && value !== void 0 && value !== null ? MASK : value;
|
|
70
|
+
}
|
|
71
|
+
function settingEntry(context, setting) {
|
|
72
|
+
const layers = {};
|
|
73
|
+
for (const scope of PRECEDENCE) {
|
|
74
|
+
if (!setting.scopes.includes(scope) || layerFile(context, scope, setting) === null) continue;
|
|
75
|
+
const value = valueAt(layerSettings(context, scope, setting), setting.key);
|
|
76
|
+
if (value !== void 0) layers[scope] = masked(setting, value);
|
|
77
|
+
}
|
|
78
|
+
const envValue = setting.env ? context.env[setting.env] : void 0;
|
|
79
|
+
const env = setting.env && envValue ? {
|
|
80
|
+
name: setting.env,
|
|
81
|
+
value: String(masked(setting, envValue))
|
|
82
|
+
} : void 0;
|
|
83
|
+
const scopedHome = !env && setting.scopedHomeValue !== void 0 && context.env.STIM_HOME;
|
|
84
|
+
const winner = PRECEDENCE.find((scope) => scope in layers);
|
|
85
|
+
let value = null;
|
|
86
|
+
let origin = null;
|
|
87
|
+
if (env) {
|
|
88
|
+
value = env.value;
|
|
89
|
+
origin = "env";
|
|
90
|
+
} else if (scopedHome) {
|
|
91
|
+
value = setting.scopedHomeValue;
|
|
92
|
+
origin = "env";
|
|
93
|
+
} else if (winner) {
|
|
94
|
+
value = layers[winner];
|
|
95
|
+
origin = winner;
|
|
96
|
+
} else if (setting.default !== void 0) {
|
|
97
|
+
value = setting.default;
|
|
98
|
+
origin = "default";
|
|
99
|
+
}
|
|
100
|
+
return {
|
|
101
|
+
key: setting.key,
|
|
102
|
+
value,
|
|
103
|
+
origin,
|
|
104
|
+
layers,
|
|
105
|
+
...env ? { env } : scopedHome ? { env: {
|
|
106
|
+
name: "STIM_HOME",
|
|
107
|
+
value: context.env.STIM_HOME
|
|
108
|
+
} } : {},
|
|
109
|
+
...setting.sensitive ? { sensitive: true } : {}
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
function unknownEntries(context) {
|
|
113
|
+
const sources = [
|
|
114
|
+
{
|
|
115
|
+
scope: "machine",
|
|
116
|
+
file: layerFile(context, "machine", null),
|
|
117
|
+
settings: { optimizations: context.machine?.optimizations }
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
scope: "workspace",
|
|
121
|
+
file: layerFile(context, "workspace", null),
|
|
122
|
+
settings: layerSettings(context, "workspace", null)
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
scope: "repo",
|
|
126
|
+
file: layerFile(context, "repo", null),
|
|
127
|
+
settings: layerSettings(context, "repo", null)
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
scope: "committed",
|
|
131
|
+
file: layerFile(context, "committed", null),
|
|
132
|
+
settings: layerSettings(context, "committed", null)
|
|
133
|
+
}
|
|
134
|
+
];
|
|
135
|
+
const repository = repositoryDirectory(context);
|
|
136
|
+
if (repository && repository !== appDirectory(context)) sources.push({
|
|
137
|
+
scope: "committed",
|
|
138
|
+
file: join(repository, ".stim.json"),
|
|
139
|
+
settings: readCommittedSettings(repository)
|
|
140
|
+
});
|
|
141
|
+
return sources.flatMap(({ scope, file, settings }) => file === null ? [] : unknownSettingKeys(settings).map((key) => ({
|
|
142
|
+
key,
|
|
143
|
+
scope,
|
|
144
|
+
file,
|
|
145
|
+
value: valueAt(settings, key)
|
|
146
|
+
})));
|
|
147
|
+
}
|
|
148
|
+
function settingsPayload(context) {
|
|
149
|
+
const files = {};
|
|
150
|
+
for (const scope of SETTING_SCOPES) {
|
|
151
|
+
const file = layerFile(context, scope, null);
|
|
152
|
+
if (file) files[scope] = file;
|
|
153
|
+
}
|
|
154
|
+
return {
|
|
155
|
+
project: context.projectPath,
|
|
156
|
+
files,
|
|
157
|
+
settings: SETTINGS.map((setting) => settingEntry(context, setting)),
|
|
158
|
+
unknown: unknownEntries(context)
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
function requireSetting(key) {
|
|
162
|
+
const setting = settingDefinition(key);
|
|
163
|
+
if (setting) return setting;
|
|
164
|
+
throw new Refusal("STIM_BAD_ARG", `${JSON.stringify(key)} is not a Stim setting.`, "Run `stim settings` to list every setting, or `stim guide settings` for what each one does.");
|
|
165
|
+
}
|
|
166
|
+
function readScope(raw, setting) {
|
|
167
|
+
if (raw === void 0) {
|
|
168
|
+
if (setting.scopes.length === 1) return setting.scopes[0];
|
|
169
|
+
throw new Refusal("STIM_BAD_ARG", `${setting.key} can live in more than one layer, so the command needs --scope.`, `Pass --scope ${setting.scopes.join("|")}.`);
|
|
170
|
+
}
|
|
171
|
+
if (!SETTING_SCOPES.includes(raw)) throw new Refusal("STIM_BAD_ARG", `--scope takes ${SETTING_SCOPES.join(", ")}, not ${JSON.stringify(raw)}.`, null);
|
|
172
|
+
const scope = raw;
|
|
173
|
+
if (!setting.scopes.includes(scope)) throw new Refusal("STIM_BAD_ARG", `${setting.key} is not read from the ${scope} layer.`, `Pass --scope ${setting.scopes.join("|")}.`);
|
|
174
|
+
return scope;
|
|
175
|
+
}
|
|
176
|
+
function requireLayer(context, scope, setting) {
|
|
177
|
+
const file = layerFile(context, scope, setting);
|
|
178
|
+
if (file) return file;
|
|
179
|
+
if (scope === "repo") throw new Refusal("STIM_BAD_ARG", "The repo layer is keyed by a Git repository, and this directory is not inside one.", "Run this from inside the repository, or pick another --scope.");
|
|
180
|
+
throw new Refusal(NO_PROJECT_REFUSAL.code, NO_PROJECT_REFUSAL.message, NO_PROJECT_REFUSAL.remedy);
|
|
181
|
+
}
|
|
182
|
+
function example(setting) {
|
|
183
|
+
switch (setting.type.kind) {
|
|
184
|
+
case "boolean": return "false";
|
|
185
|
+
case "number": return String(setting.default ?? setting.type.minimum ?? 1);
|
|
186
|
+
case "strings": return `'["node_modules"]'`;
|
|
187
|
+
case "object": return `'{"key": "value"}'`;
|
|
188
|
+
case "choice": return setting.type.choices[0];
|
|
189
|
+
default: return "<value>";
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
function parseSettingValue(setting, raw) {
|
|
193
|
+
const invalid = (expected) => new Refusal("STIM_BAD_ARG", `Invalid ${setting.key} value ${JSON.stringify(raw)}. Expected ${expected}.`, `For example: stim settings set ${setting.key} ${example(setting)}${setting.scopes.length > 1 ? ` --scope ${setting.scopes[0]}` : ""}`);
|
|
194
|
+
let value = raw;
|
|
195
|
+
const kind = setting.type.kind;
|
|
196
|
+
if (kind === "boolean" || kind === "number" || kind === "strings" || kind === "object") try {
|
|
197
|
+
value = JSON.parse(raw);
|
|
198
|
+
} catch {
|
|
199
|
+
value = raw;
|
|
200
|
+
}
|
|
201
|
+
const error = settingValueError(setting, value);
|
|
202
|
+
if (error) throw invalid(kind === "strings" || kind === "object" ? `${error}, written as JSON` : error);
|
|
203
|
+
return value;
|
|
204
|
+
}
|
|
205
|
+
function committedTarget(context, setting) {
|
|
206
|
+
const directory = committedDirectory(context, setting);
|
|
207
|
+
if (!directory) throw new Refusal(NO_PROJECT_REFUSAL.code, NO_PROJECT_REFUSAL.message, NO_PROJECT_REFUSAL.remedy);
|
|
208
|
+
return join(directory, ".stim.json");
|
|
209
|
+
}
|
|
210
|
+
function writeCommitted(file, key, value) {
|
|
211
|
+
return withConfigLock(() => {
|
|
212
|
+
const exists = existsSync(file);
|
|
213
|
+
const text = exists ? readFileSync(file, "utf-8") : "";
|
|
214
|
+
let parsed = {};
|
|
215
|
+
if (exists && text.trim() !== "") try {
|
|
216
|
+
parsed = JSON.parse(text);
|
|
217
|
+
} catch (error) {
|
|
218
|
+
throw new Refusal("STIM_BAD_ARG", `${file} is not valid JSON: ${error.message}`, `Repair ${file}, then run the command again.`);
|
|
219
|
+
}
|
|
220
|
+
if (!isJsonObject(parsed)) throw new Refusal("STIM_BAD_ARG", `${file} is not a JSON object.`, `Repair ${file}, then run the command again.`);
|
|
221
|
+
const parts = key.split(".");
|
|
222
|
+
const chain = [parsed];
|
|
223
|
+
for (const part of parts.slice(0, -1)) {
|
|
224
|
+
const node = chain.at(-1);
|
|
225
|
+
if (!isJsonObject(node[part])) {
|
|
226
|
+
if (value === void 0) return false;
|
|
227
|
+
node[part] = {};
|
|
228
|
+
}
|
|
229
|
+
chain.push(node[part]);
|
|
230
|
+
}
|
|
231
|
+
const leaf = parts.at(-1);
|
|
232
|
+
const parent = chain.at(-1);
|
|
233
|
+
if (value === void 0) {
|
|
234
|
+
if (!(leaf in parent)) return false;
|
|
235
|
+
delete parent[leaf];
|
|
236
|
+
for (let index = chain.length - 1; index > 0; index--) {
|
|
237
|
+
if (Object.keys(chain[index]).length > 0) break;
|
|
238
|
+
delete chain[index - 1][parts[index - 1]];
|
|
239
|
+
}
|
|
240
|
+
} else parent[leaf] = value;
|
|
241
|
+
const indent = /\n([ \t]+)"/.exec(text)?.[1] ?? 2;
|
|
242
|
+
const tmp = `${file}.${process.pid}.${Math.random().toString(36).slice(2)}.tmp`;
|
|
243
|
+
writeFileSync(tmp, `${JSON.stringify(parsed, null, indent)}\n`);
|
|
244
|
+
try {
|
|
245
|
+
renameSync(tmp, file);
|
|
246
|
+
} catch (error) {
|
|
247
|
+
try {
|
|
248
|
+
unlinkSync(tmp);
|
|
249
|
+
} catch {}
|
|
250
|
+
throw error;
|
|
251
|
+
}
|
|
252
|
+
return true;
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
function writeSetting(context, setting, scope, value) {
|
|
256
|
+
if (scope === "committed") return writeCommitted(committedTarget(context, setting), setting.key, value);
|
|
257
|
+
if (scope === "machine") return writeConfigSetting({ scope }, setting.key, value);
|
|
258
|
+
if (scope === "workspace") return writeConfigSetting({
|
|
259
|
+
scope,
|
|
260
|
+
projectPath: context.projectPath
|
|
261
|
+
}, setting.key, value);
|
|
262
|
+
return writeConfigSetting({
|
|
263
|
+
scope,
|
|
264
|
+
gitCommonDir: context.gitCommonDir
|
|
265
|
+
}, setting.key, value);
|
|
266
|
+
}
|
|
267
|
+
function formatValue(value) {
|
|
268
|
+
return typeof value === "string" ? value : JSON.stringify(value);
|
|
269
|
+
}
|
|
270
|
+
const CONSOLE = {
|
|
271
|
+
out: (line) => console.log(line),
|
|
272
|
+
note: (line) => console.error(line)
|
|
273
|
+
};
|
|
274
|
+
function run(json, io, action) {
|
|
275
|
+
try {
|
|
276
|
+
action();
|
|
277
|
+
} catch (error) {
|
|
278
|
+
const code = error.code;
|
|
279
|
+
if (!(error instanceof Refusal) && !(typeof code === "string" && code.startsWith("STIM_"))) throw error;
|
|
280
|
+
const failure = {
|
|
281
|
+
code,
|
|
282
|
+
message: error.message,
|
|
283
|
+
remedy: error instanceof Refusal ? error.remedy : null
|
|
284
|
+
};
|
|
285
|
+
io.note(chalk.red(`${failure.code}: ${failure.message}`));
|
|
286
|
+
if (failure.remedy) io.note(chalk.dim(failure.remedy));
|
|
287
|
+
if (json) io.out(JSON.stringify(failure));
|
|
288
|
+
process.exitCode = 1;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
function wantsJson(opts, command) {
|
|
292
|
+
return Boolean(opts.json ?? command.parent?.opts().json);
|
|
293
|
+
}
|
|
294
|
+
function registerSettings(program, io = CONSOLE, env = process.env) {
|
|
295
|
+
const settings = program.command("settings").description("Show every Stim setting with its effective value and layer, or change one").option("--json", "print every setting, its origin, and each layer value as JSON").action((opts) => run(Boolean(opts.json), io, () => {
|
|
296
|
+
const payload = settingsPayload(readContext(env));
|
|
297
|
+
if (opts.json) {
|
|
298
|
+
io.out(JSON.stringify(payload));
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
const width = Math.max(...payload.settings.map((entry) => entry.key.length));
|
|
302
|
+
for (const entry of payload.settings) {
|
|
303
|
+
const origin = entry.origin ?? "unset";
|
|
304
|
+
const shown = entry.origin === null ? "" : formatValue(entry.value);
|
|
305
|
+
io.out(`${entry.key.padEnd(width)} ${shown}${shown ? " " : ""}${chalk.dim(`(${origin})`)}`);
|
|
306
|
+
}
|
|
307
|
+
for (const entry of payload.unknown) io.note(chalk.yellow(`Warning: ${entry.key} in ${entry.file} is not read by Stim.`));
|
|
308
|
+
}));
|
|
309
|
+
settings.command("get <key>").description("Print the effective value of a setting, or its value in one layer").option("--scope <scope>", `read one layer: ${SETTING_SCOPES.join(", ")}`).option("--json", "print the setting entry as JSON").action((key, opts, command) => run(wantsJson(opts, command), io, () => {
|
|
310
|
+
const setting = requireSetting(key);
|
|
311
|
+
const scope = opts.scope === void 0 ? null : readScope(opts.scope, setting);
|
|
312
|
+
const context = readContext(env);
|
|
313
|
+
const entry = settingEntry(context, setting);
|
|
314
|
+
const value = scope ? entry.layers[scope] ?? null : entry.value;
|
|
315
|
+
if (wantsJson(opts, command)) {
|
|
316
|
+
io.out(JSON.stringify(scope ? {
|
|
317
|
+
key,
|
|
318
|
+
scope,
|
|
319
|
+
file: layerFile(context, scope, setting),
|
|
320
|
+
value
|
|
321
|
+
} : entry));
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
if (value !== null) io.out(formatValue(value));
|
|
325
|
+
}));
|
|
326
|
+
settings.command("set <key> <value>").description("Write a setting to one layer").option("--scope <scope>", `the layer to write: ${SETTING_SCOPES.join(", ")}`).option("--json", "print the written setting as JSON").action((key, raw, opts, command) => run(wantsJson(opts, command), io, () => {
|
|
327
|
+
const setting = requireSetting(key);
|
|
328
|
+
const scope = readScope(opts.scope, setting);
|
|
329
|
+
const value = parseSettingValue(setting, raw);
|
|
330
|
+
if (setting.sensitive && scope === "committed" && !isSensitiveReference(value)) throw new Refusal("STIM_BAD_ARG", `${key} is sensitive, so a committed .stim.json takes only an env: or file: reference, never the secret.`, `Set the secret with --scope workspace or --scope repo, or commit a reference such as env:MY_KEYSTORE_PASSWORD.`);
|
|
331
|
+
const context = readContext(env);
|
|
332
|
+
const file = requireLayer(context, scope, setting);
|
|
333
|
+
const changed = writeSetting(context, setting, scope, value);
|
|
334
|
+
report(io, wantsJson(opts, command), {
|
|
335
|
+
key,
|
|
336
|
+
scope,
|
|
337
|
+
file,
|
|
338
|
+
changed
|
|
339
|
+
}, setting, readContext(env), "set");
|
|
340
|
+
}));
|
|
341
|
+
settings.command("unset <key>").description("Remove a setting from one layer").option("--scope <scope>", `the layer to clear: ${SETTING_SCOPES.join(", ")}`).option("--json", "print the setting after removal as JSON").action((key, opts, command) => run(wantsJson(opts, command), io, () => {
|
|
342
|
+
const setting = requireSetting(key);
|
|
343
|
+
const scope = readScope(opts.scope, setting);
|
|
344
|
+
const context = readContext(env);
|
|
345
|
+
const file = requireLayer(context, scope, setting);
|
|
346
|
+
const changed = writeSetting(context, setting, scope, void 0);
|
|
347
|
+
report(io, wantsJson(opts, command), {
|
|
348
|
+
key,
|
|
349
|
+
scope,
|
|
350
|
+
file,
|
|
351
|
+
changed
|
|
352
|
+
}, setting, readContext(env), "unset");
|
|
353
|
+
}));
|
|
354
|
+
}
|
|
355
|
+
function report(io, json, write, setting, context, verb) {
|
|
356
|
+
const entry = settingEntry(context, setting);
|
|
357
|
+
if (json) {
|
|
358
|
+
io.out(JSON.stringify({
|
|
359
|
+
...write,
|
|
360
|
+
setting: entry
|
|
361
|
+
}));
|
|
362
|
+
return;
|
|
363
|
+
}
|
|
364
|
+
const effective = entry.origin === null ? "unset" : `${formatValue(entry.value)} (${entry.origin})`;
|
|
365
|
+
if (!write.changed) {
|
|
366
|
+
io.out(`${write.key} was not set in ${write.file}; effective value: ${effective}`);
|
|
367
|
+
return;
|
|
368
|
+
}
|
|
369
|
+
const shown = verb === "set" ? ` = ${formatValue(entry.layers[write.scope])}` : "";
|
|
370
|
+
io.out(`${verb} ${write.key}${shown} in ${write.file}; effective value: ${effective}`);
|
|
371
|
+
}
|
|
372
|
+
function settingsCommand(program) {
|
|
373
|
+
registerSettings(program);
|
|
374
|
+
}
|
|
375
|
+
//#endregion
|
|
376
|
+
export { settingsCommand as default, registerSettings };
|