






















@@ -27,6 +27,12 @@ const plistUnescape = (value: string): string =>
2727.replaceAll("<", "<")
2828.replaceAll("&", "&");
292930+type ReadLaunchAgentProgramArgumentsOptions = {
31+expectedEnvironmentWrapperPath?: string;
32+expectedEnvironmentFilePath?: string;
33+generatedEnvironmentLabel?: string;
34+};
35+3036function parseGeneratedEnvValue(value: string): string {
3137const trimmed = value.trim();
3238if (!trimmed.startsWith("'") || !trimmed.endsWith("'")) {
@@ -35,17 +41,93 @@ function parseGeneratedEnvValue(value: string): string {
3541return trimmed.slice(1, -1).replaceAll("'\\''", "'");
3642}
374344+function includesGeneratedEnvironmentPathToken(value: string | undefined, token: string): boolean {
45+return Boolean(value?.replaceAll("\\", "/").includes(token));
46+}
47+48+function includesGeneratedEnvironmentDirToken(value: string | undefined): boolean {
49+return Boolean(value?.replaceAll("\\", "/").includes("/service-env/"));
50+}
51+52+function resolveSiblingGeneratedEnvFilePath(
53+envFilePath: string,
54+options?: ReadLaunchAgentProgramArgumentsOptions,
55+): string | undefined {
56+const label = options?.generatedEnvironmentLabel?.trim();
57+if (!label) {
58+return undefined;
59+}
60+const serviceEnvMarker = "/service-env/";
61+const markerIndex = envFilePath.replaceAll("\\", "/").lastIndexOf(serviceEnvMarker);
62+if (markerIndex < 0) {
63+return undefined;
64+}
65+// Custom state dirs can also contain service-env; use the generated env dir closest to the file.
66+const serviceEnvDirEnd = markerIndex + serviceEnvMarker.length - 1;
67+return `${envFilePath.slice(0, serviceEnvDirEnd)}/${label}.env`;
68+}
69+70+function isGeneratedEnvWrapperArgs(
71+programArguments: string[],
72+options?: ReadLaunchAgentProgramArgumentsOptions,
73+): boolean {
74+const wrapperPath = programArguments[0];
75+const envFilePath = programArguments[1];
76+if (!wrapperPath || !envFilePath) {
77+return false;
78+}
79+if (!options) {
80+return wrapperPath.endsWith("-env-wrapper.sh");
81+}
82+if (
83+options.expectedEnvironmentWrapperPath &&
84+options.expectedEnvironmentFilePath &&
85+wrapperPath === options.expectedEnvironmentWrapperPath &&
86+envFilePath === options.expectedEnvironmentFilePath
87+) {
88+return true;
89+}
90+const label = options.generatedEnvironmentLabel?.trim();
91+if (!label) {
92+return false;
93+}
94+// Legacy/corrupted plists may preserve the label-derived wrapper name inside
95+// a mangled service-env path. Still unwrap it so the next rewrite can repair.
96+return (
97+includesGeneratedEnvironmentDirToken(wrapperPath) &&
98+includesGeneratedEnvironmentDirToken(envFilePath) &&
99+includesGeneratedEnvironmentPathToken(wrapperPath, `${label}-env-wrapper.sh`) &&
100+includesGeneratedEnvironmentPathToken(envFilePath, `${label}.env`)
101+);
102+}
103+38104async function readLaunchAgentEnvironmentFile(
39105programArguments: string[],
106+options?: ReadLaunchAgentProgramArgumentsOptions,
40107): Promise<Record<string, string>> {
41108const envFilePath = programArguments[1];
42-if (!programArguments[0]?.endsWith("-env-wrapper.sh") || !envFilePath) {
109+if (!isGeneratedEnvWrapperArgs(programArguments, options) || !envFilePath) {
43110return {};
44111}
45112let content = "";
46-try {
47-content = await fs.readFile(envFilePath, "utf8");
48-} catch {
113+const candidateEnvFilePaths = Array.from(
114+new Set(
115+[
116+envFilePath,
117+resolveSiblingGeneratedEnvFilePath(envFilePath, options),
118+options?.expectedEnvironmentFilePath,
119+].filter((candidate): candidate is string => Boolean(candidate)),
120+),
121+);
122+for (const candidate of candidateEnvFilePaths) {
123+try {
124+content = await fs.readFile(candidate, "utf8");
125+break;
126+} catch {
127+// Keep trying; mangled wrapper args may still have the canonical env file.
128+}
129+}
130+if (!content) {
49131return {};
50132}
51133const environment: Record<string, string> = {};
@@ -68,8 +150,11 @@ async function readLaunchAgentEnvironmentFile(
68150return environment;
69151}
7015271-function unwrapGeneratedEnvWrapperArgs(programArguments: string[]): string[] {
72-if (!programArguments[0]?.endsWith("-env-wrapper.sh") || !programArguments[1]) {
153+function unwrapGeneratedEnvWrapperArgs(
154+programArguments: string[],
155+options?: ReadLaunchAgentProgramArgumentsOptions,
156+): string[] {
157+if (!isGeneratedEnvWrapperArgs(programArguments, options)) {
73158return programArguments;
74159}
75160return programArguments.slice(2);
@@ -100,6 +185,26 @@ export async function readLaunchAgentProgramArgumentsFromFile(plistPath: string)
100185environment?: Record<string, string>;
101186environmentValueSources?: Record<string, GatewayServiceEnvironmentValueSource>;
102187sourcePath?: string;
188+} | null>;
189+export async function readLaunchAgentProgramArgumentsFromFile(
190+plistPath: string,
191+options: ReadLaunchAgentProgramArgumentsOptions,
192+): Promise<{
193+programArguments: string[];
194+workingDirectory?: string;
195+environment?: Record<string, string>;
196+environmentValueSources?: Record<string, GatewayServiceEnvironmentValueSource>;
197+sourcePath?: string;
198+} | null>;
199+export async function readLaunchAgentProgramArgumentsFromFile(
200+plistPath: string,
201+options?: ReadLaunchAgentProgramArgumentsOptions,
202+): Promise<{
203+programArguments: string[];
204+workingDirectory?: string;
205+environment?: Record<string, string>;
206+environmentValueSources?: Record<string, GatewayServiceEnvironmentValueSource>;
207+sourcePath?: string;
103208} | null> {
104209try {
105210const plist = await fs.readFile(plistPath, "utf8");
@@ -128,8 +233,8 @@ export async function readLaunchAgentProgramArgumentsFromFile(plistPath: string)
128233inlineEnvironment[key] = value;
129234}
130235}
131-const fileEnvironment = await readLaunchAgentEnvironmentFile(args);
132-const effectiveProgramArguments = unwrapGeneratedEnvWrapperArgs(args);
236+const fileEnvironment = await readLaunchAgentEnvironmentFile(args, options);
237+const effectiveProgramArguments = unwrapGeneratedEnvWrapperArgs(args, options);
133238const environment = { ...inlineEnvironment, ...fileEnvironment };
134239const environmentValueSources: Record<string, GatewayServiceEnvironmentValueSource> = {};
135240for (const key of Object.keys(inlineEnvironment)) {
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。