diff --git a/src/resources/extensions/get-secrets-from-user.ts b/src/resources/extensions/get-secrets-from-user.ts index 9ff6cbb03..300852305 100644 --- a/src/resources/extensions/get-secrets-from-user.ts +++ b/src/resources/extensions/get-secrets-from-user.ts @@ -47,6 +47,12 @@ function shellEscapeSingle(value: string): string { return `'${value.replace(/'/g, `'\\''`)}'`; } +function hydrateProcessEnv(key: string, value: string): void { + // Make newly collected secrets immediately visible to the current session. + // Some extensions read process.env directly and do not reload .env on every call. + process.env[key] = value; +} + async function writeEnvKey(filePath: string, key: string, value: string): Promise { let content = ""; try { @@ -312,6 +318,7 @@ async function applySecrets( try { await writeEnvKey(opts.envFilePath, key, value); applied.push(key); + hydrateProcessEnv(key, value); } catch (err: any) { errors.push(`${key}: ${err.message}`); } @@ -330,6 +337,7 @@ async function applySecrets( errors.push(`${key}: ${result.stderr.slice(0, 200)}`); } else { applied.push(key); + hydrateProcessEnv(key, value); } } catch (err: any) { errors.push(`${key}: ${err.message}`); diff --git a/src/resources/extensions/gsd/tests/collect-from-manifest.test.ts b/src/resources/extensions/gsd/tests/collect-from-manifest.test.ts index c0a62946f..9ca2eecd9 100644 --- a/src/resources/extensions/gsd/tests/collect-from-manifest.test.ts +++ b/src/resources/extensions/gsd/tests/collect-from-manifest.test.ts @@ -227,6 +227,45 @@ test("collectSecretsFromManifest: manifest statuses are updated after collection "KEY_TO_SKIP should have status 'skipped' after user skipped it"); }); +test("collectSecretsFromManifest: applied keys hydrate process.env for the running session", async (t) => { + const { collectSecretsFromManifest } = await loadOrchestrator(); + + const tmp = makeTempDir("manifest-live-env"); + const envKey = "CONTEXT7_API_KEY"; + const saved = process.env[envKey]; + t.after(() => { + if (saved === undefined) delete process.env[envKey]; + else process.env[envKey] = saved; + rmSync(tmp, { recursive: true, force: true }); + }); + + delete process.env[envKey]; + + const manifest = makeManifest([ + { key: envKey, status: "pending" }, + ]); + await writeManifestFile(tmp, manifest); + + let callIndex = 0; + const mockCtx = { + cwd: tmp, + hasUI: true, + ui: { + custom: async (_factory: any) => { + callIndex++; + if (callIndex <= 1) return null; // summary screen dismiss + return "c7_live_test_key"; + }, + }, + }; + + const result = await collectSecretsFromManifest(tmp, "M001", mockCtx as any); + + assert.ok(result.applied.includes(envKey), "CONTEXT7_API_KEY should be applied"); + assert.equal(process.env[envKey], "c7_live_test_key", + "applied keys should be available through process.env without restarting"); +}); + // ─── showSecretsSummary: render output ──────────────────────────────────────── test("showSecretsSummary: produces lines with correct status glyphs for each entry status", async () => {