@runeya/runeya 2.0.146 → 2.0.148

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.
Files changed (171) hide show
  1. package/agent/index.js +10 -4
  2. package/agent/index.js.map +1 -1
  3. package/{agent-manager-R7BPQO6D.js → agent-manager-46C4NIQ2.js} +4 -2
  4. package/{chat-LPML22J5.js → chat-CMNDMXIP.js} +9 -5
  5. package/{chunk-SEPAURTQ.js → chunk-2NE52CL5.js} +156 -923
  6. package/chunk-2NE52CL5.js.map +1 -0
  7. package/chunk-4D3GCBPO.js +462 -0
  8. package/chunk-4D3GCBPO.js.map +1 -0
  9. package/{chunk-KV4GJKXU.js → chunk-5XG3X2TM.js} +27 -1479
  10. package/chunk-5XG3X2TM.js.map +1 -0
  11. package/chunk-7QXP4FXD.js +969 -0
  12. package/chunk-7QXP4FXD.js.map +1 -0
  13. package/chunk-DA2DZBTL.js +43 -0
  14. package/chunk-DA2DZBTL.js.map +1 -0
  15. package/chunk-DFPZ4MTI.js +1041 -0
  16. package/chunk-DFPZ4MTI.js.map +1 -0
  17. package/{chunk-UD42LACH.js → chunk-JNK6H5KH.js} +164 -1007
  18. package/chunk-JNK6H5KH.js.map +1 -0
  19. package/chunk-WDHLEO5S.js +809 -0
  20. package/chunk-WDHLEO5S.js.map +1 -0
  21. package/{companion-W3UMZWGH.js → companion-XKMNRIJB.js} +8 -3
  22. package/environment-resolver-ZDTF3MHI.js +18 -0
  23. package/environment-resolver-ZDTF3MHI.js.map +1 -0
  24. package/index.js +7 -7
  25. package/{install-gate-PVMGJDWE.js → install-gate-PWPGC63Z.js} +2 -2
  26. package/mcp-ready-TAPBAOZY.js +9 -0
  27. package/mcp-ready-TAPBAOZY.js.map +1 -0
  28. package/mcp-server/index.js +24 -0
  29. package/mcp-server/index.js.map +1 -1
  30. package/mcp-server/launch.d.ts +6 -0
  31. package/mcp-server/launch.js +2 -1
  32. package/mcp-server/launch.js.map +1 -1
  33. package/package.json +1 -1
  34. package/project-store-FLXTAD3J.js +23 -0
  35. package/project-store-FLXTAD3J.js.map +1 -0
  36. package/{src-LEDGW5KP.js → src-I5TPC6GW.js} +155 -63
  37. package/src-I5TPC6GW.js.map +1 -0
  38. package/web/assets/{AgentScalarChatInterface.vue-BYszptaB.js → AgentScalarChatInterface.vue-DKBinB_l.js} +2 -2
  39. package/web/assets/AgentTerminalPage-CixU7x6O.js +1 -0
  40. package/web/assets/AiChatModals-BvGUd-QD.css +1 -0
  41. package/web/assets/AiChatModals-C-hXImkO.js +4 -0
  42. package/web/assets/AppLayout-At9wk0sx.js +1 -0
  43. package/web/assets/{AppLayout-tsw5Ow0w.css → AppLayout-BlhwflMq.css} +1 -1
  44. package/web/assets/AuditPage-BkqbHxjY.js +1 -0
  45. package/web/assets/CloudAccountPage-D5C2SCS9.js +1 -0
  46. package/web/assets/CloudMessagingPage-Bi57GGHO.js +2 -0
  47. package/web/assets/DashboardPage-dEQop9ql.js +1 -0
  48. package/web/assets/DirectoryPickerDialog-DIMSeDhw.js +1 -0
  49. package/web/assets/{EditorIcon-CypGLV6w.js → EditorIcon-W3Szca4J.js} +1 -1
  50. package/web/assets/EnvironmentForm-C5emavNh.js +1 -0
  51. package/web/assets/EnvironmentFormPage-BIoy8fsW.js +1 -0
  52. package/web/assets/EnvironmentListPage-BDYeh7XF.js +1 -0
  53. package/web/assets/{FlagChip-R_T5qYpL.js → FlagChip-DPtIBCjQ.js} +1 -1
  54. package/web/assets/KanbanBoardPage-BlCcjBwV.js +4 -0
  55. package/web/assets/KanbanListPage-DbXONxfC.js +1 -0
  56. package/web/assets/LaunchProjectPage-Cg92hHwQ.js +1 -0
  57. package/web/assets/LaunchServicesPage-CO8gOB9D.js +1 -0
  58. package/web/assets/LaunchServicesPage-h5o3zLcy.css +1 -0
  59. package/web/assets/{LaunchShell-DUrSunB4.js → LaunchShell-CDb21ihZ.js} +1 -1
  60. package/web/assets/LogViewer-DsusKk2b.js +3 -0
  61. package/web/assets/OrgKeyPrompt-CX9K7r9I.js +1 -0
  62. package/web/assets/ProcessControls-B7hWVqiR.css +1 -0
  63. package/web/assets/ProcessControls-TEZutuxq.js +1 -0
  64. package/web/assets/ProcessDetailPage-Cj23FECq.js +1 -0
  65. package/web/assets/ProcessMetrics-1P6iE2Il.js +1 -0
  66. package/web/assets/ProjectCreateDialog-D3aMWKfw.js +1 -0
  67. package/web/assets/{ProjectLocationGate-DhMVdIjN.js → ProjectLocationGate-DU0Jj8Nw.js} +1 -1
  68. package/web/assets/ProjectPublishDialog-D7sNKei3.js +1 -0
  69. package/web/assets/{RandomJobTestPage-BUS2Ty6-.js → RandomJobTestPage-DQUMRHyf.js} +1 -1
  70. package/web/assets/{ScenarioEditorPage-vMoRt0Qn.css → ScenarioEditorPage-BSjSX4bw.css} +1 -1
  71. package/web/assets/ScenarioEditorPage-DvCdcY9m.js +14 -0
  72. package/web/assets/SendToChatDialog-BdWKjYmv.js +1 -0
  73. package/web/assets/ServiceControlsBar-B_J5m-Kc.js +1 -0
  74. package/web/assets/ServiceDetailPage-DhJcjFfY.js +2 -0
  75. package/web/assets/{ServiceDetailPage-COdaCZ6r.css → ServiceDetailPage-DnSf5cm9.css} +1 -1
  76. package/web/assets/ServiceFormPage-fp8NCHSv.js +1 -0
  77. package/web/assets/{SettingsPage-4pKUgKPm.css → SettingsPage-NH2fQap4.css} +1 -1
  78. package/web/assets/SettingsPage-s28BodWe.js +2086 -0
  79. package/web/assets/UnlockPage-BXXIPHW_.js +1 -0
  80. package/web/assets/VaultMigrationPage-BfNuKtkJ.js +1 -0
  81. package/web/assets/{VersionBadge-BmArk24p.js → VersionBadge-CW7czacg.js} +1 -1
  82. package/web/assets/{WikiPage-DADu8WUA.js → WikiPage-BiwpCM3E.js} +1 -1
  83. package/web/assets/WikiView-CMch_06Z.js +1 -0
  84. package/web/assets/{add-scalar-classes-dWEWPlFD.js → add-scalar-classes-Ckanjq1h.js} +14 -14
  85. package/web/assets/{agent.store-CKLAkF9a.js → agent.store-piokQ9Dt.js} +1 -1
  86. package/web/assets/{auth-Cg9BWTfK.js → auth-BT_jf-5e.js} +2 -2
  87. package/web/assets/cloud-chat.store-CDKh4tIy.js +1 -0
  88. package/web/assets/{cloud-client-D_zCiW0s.js → cloud-client-CzPdZLDq.js} +2 -2
  89. package/web/assets/{cloud-session-DOaDpZTy.js → cloud-session-BYfn6YM4.js} +2 -2
  90. package/web/assets/floating-ui.dom-DF3oyfHd.js +1 -0
  91. package/web/assets/i18n-D0FT7rCj.js +1 -0
  92. package/web/assets/index-3LTzgeU-.css +1 -0
  93. package/web/assets/index-Ci2CNnit.js +309 -0
  94. package/web/assets/modal-iRaP1izE.js +5 -0
  95. package/web/assets/notification.store-CvvuTBVz.js +1 -0
  96. package/web/assets/{project-launch.store-y7JBMNiE.js → project-launch.store-CTmbl8UY.js} +1 -1
  97. package/web/assets/{project.store-DGJr0Qr9.js → project.store-CNC6_4r4.js} +1 -1
  98. package/web/assets/runtime-dom.esm-bundler-CyEVRK6B.js +1 -0
  99. package/web/assets/scenario.store-BIFQPXgl.js +7 -0
  100. package/web/assets/{service.store-5jWsJxPx.js → service.store-B40U4QzI.js} +1 -1
  101. package/web/assets/settings-scope-CyWMCjRY.js +1 -0
  102. package/web/assets/settings.store-Dw6bAoWE.js +1 -0
  103. package/web/assets/{src-Dnwk6NpV.js → src-CrNi4Pjg.js} +3 -3
  104. package/web/assets/src-DIBHat7I.js +3 -0
  105. package/web/assets/src-DtCW_XCh.js +1 -0
  106. package/web/assets/{trpc-Drabzwpd.js → trpc-BAZGRZBD.js} +3 -3
  107. package/web/assets/{useCloudOrg-BAQEtFPl.js → useCloudOrg-EnXFBwt1.js} +1 -1
  108. package/web/assets/useEnvVarAutocomplete-BxJh2Lw0.js +1 -0
  109. package/web/assets/useProjectCatalog-BrvUGv9A.js +1 -0
  110. package/web/assets/{useProjectCloudOrg-CEN9-_OA.js → useProjectCloudOrg-Czxlg00k.js} +1 -1
  111. package/web/assets/{useServiceUrlHost-BuoPEXZX.js → useServiceUrlHost-Szz9y3rh.js} +1 -1
  112. package/web/assets/vue-i18n-o7yraQpR.js +3 -0
  113. package/web/index.html +21 -21
  114. package/chunk-KV4GJKXU.js.map +0 -1
  115. package/chunk-SEPAURTQ.js.map +0 -1
  116. package/chunk-UD42LACH.js.map +0 -1
  117. package/src-LEDGW5KP.js.map +0 -1
  118. package/web/assets/AgentTerminalPage-C3TJ1NL9.js +0 -1
  119. package/web/assets/AiChatModals-D3scRE3S.js +0 -4
  120. package/web/assets/AiChatModals-EfRuvId7.css +0 -1
  121. package/web/assets/AppLayout-BMQUjPKe.js +0 -1
  122. package/web/assets/AuditPage-CKcExBws.js +0 -1
  123. package/web/assets/CloudAccountPage-B6oPg0BZ.js +0 -1
  124. package/web/assets/CloudMessagingPage-C5fwVe-F.js +0 -2
  125. package/web/assets/DashboardPage-9RV7sx3e.js +0 -1
  126. package/web/assets/DirectoryPickerDialog-C06BXyfJ.js +0 -1
  127. package/web/assets/EnvironmentForm-CAvDoira.js +0 -1
  128. package/web/assets/EnvironmentFormPage-BmAxhN-m.js +0 -1
  129. package/web/assets/EnvironmentListPage-B8uATPBI.js +0 -1
  130. package/web/assets/KanbanBoardPage-CQsOkRUf.js +0 -4
  131. package/web/assets/KanbanListPage-CWZqkjD6.js +0 -1
  132. package/web/assets/LaunchProjectPage-saSmC7Pr.js +0 -1
  133. package/web/assets/LaunchServicesPage-BkKyLMEz.js +0 -1
  134. package/web/assets/LaunchServicesPage-DoLDPqQq.css +0 -1
  135. package/web/assets/LogViewer-CZBYkH9J.js +0 -3
  136. package/web/assets/OrgKeyPrompt-DzQ7pwbs.js +0 -1
  137. package/web/assets/ProcessControls-BEeoNlNV.js +0 -1
  138. package/web/assets/ProcessControls-BlpnVylq.css +0 -1
  139. package/web/assets/ProcessDetailPage-CQgu5uKm.js +0 -1
  140. package/web/assets/ProcessMetrics-Crlfkelj.js +0 -1
  141. package/web/assets/ProjectCreateDialog-BolrhRD-.js +0 -1
  142. package/web/assets/ProjectPublishDialog-DsZNWrfz.js +0 -1
  143. package/web/assets/ScenarioEditorPage-MIAGh2us.js +0 -14
  144. package/web/assets/SendToChatDialog-BxWsyv29.js +0 -1
  145. package/web/assets/ServiceControlsBar-DqDPAZt7.js +0 -1
  146. package/web/assets/ServiceDetailPage-hkSAzZ-l.js +0 -2
  147. package/web/assets/ServiceFormPage-DXqhqXg8.js +0 -1
  148. package/web/assets/SettingsPage-DS2YhMIM.js +0 -2086
  149. package/web/assets/UnlockPage-s8SgVcKk.js +0 -1
  150. package/web/assets/VaultMigrationPage-s0b44MDM.js +0 -1
  151. package/web/assets/WikiView-DtGwIt_Q.js +0 -1
  152. package/web/assets/cloud-chat.store-b-BHGz7I.js +0 -1
  153. package/web/assets/editor.store-DCAZSeVG.js +0 -1
  154. package/web/assets/floating-ui.dom-DWhsZyqT.js +0 -1
  155. package/web/assets/i18n-D0afQEGs.js +0 -1
  156. package/web/assets/index-D8VRbyoP.js +0 -309
  157. package/web/assets/index-DsezNbSM.css +0 -1
  158. package/web/assets/modal-qYgTMkYb.js +0 -5
  159. package/web/assets/scenario.store-YWHL2_wu.js +0 -7
  160. package/web/assets/settings-scope-Bv7QGPrt.js +0 -1
  161. package/web/assets/settings.store-bEsB7oKb.js +0 -1
  162. package/web/assets/src--GO-VSJ0.js +0 -5
  163. package/web/assets/src-C-D_y7ou.js +0 -1
  164. package/web/assets/useEnvVarAutocomplete-BqGTODUv.js +0 -1
  165. package/web/assets/useProjectCatalog-yocjIKt6.js +0 -1
  166. package/web/assets/vue-draggable-plus-BHsveB8w.css +0 -1
  167. package/web/assets/vue-draggable-plus-DX4rTBiu.js +0 -1
  168. /package/{agent-manager-R7BPQO6D.js.map → agent-manager-46C4NIQ2.js.map} +0 -0
  169. /package/{chat-LPML22J5.js.map → chat-CMNDMXIP.js.map} +0 -0
  170. /package/{companion-W3UMZWGH.js.map → companion-XKMNRIJB.js.map} +0 -0
  171. /package/{install-gate-PVMGJDWE.js.map → install-gate-PWPGC63Z.js.map} +0 -0
@@ -0,0 +1,809 @@
1
+ import {
2
+ StoreDiskCoordinator,
3
+ decryptVariableSlots,
4
+ encryptVariableSlots,
5
+ ensureProjectsLoaded,
6
+ environmentStore,
7
+ extractEncryptedVariableSlots,
8
+ getEncryptionKey
9
+ } from "./chunk-DFPZ4MTI.js";
10
+ import {
11
+ fingerprintFiles,
12
+ renameWithRetry
13
+ } from "./chunk-4LJQIQMN.js";
14
+ import {
15
+ allVaultRoots,
16
+ keyedFilePath,
17
+ legacyMachineFilePath,
18
+ vaultIdOfRoot
19
+ } from "./chunk-VPSQJOSN.js";
20
+ import {
21
+ MASKED_VALUE,
22
+ isSharedWithAi
23
+ } from "./chunk-MZSDTA4A.js";
24
+
25
+ // ../server/src/services/environment-overrides-store.ts
26
+ import { readFile, writeFile, mkdir, chmod } from "fs/promises";
27
+ import { dirname, join } from "path";
28
+ var FILENAME = "environment-overrides.json";
29
+ var EnvironmentOverridesStore = class {
30
+ data = {};
31
+ loaded = false;
32
+ /**
33
+ * Le coordinateur partagé par les stores : un seul rechargement à la fois,
34
+ * jamais pendant une écriture, et une substitution atomique à la fin.
35
+ *
36
+ * Ce store faisait sa propre cuisine et se marquait « chargé » avant ses
37
+ * `await` : toute lecture concurrente repartait avec une table vide — une
38
+ * surcharge déjà écrite paraissait absente, et l'assistant réclamait au
39
+ * déverrouillage des variables que ce poste avait déjà renseignées.
40
+ */
41
+ disk = new StoreDiskCoordinator();
42
+ /** Ce que le disque portait au dernier chargement (cf. `load`). */
43
+ fingerprint = "";
44
+ diskEncryptedSlots = {};
45
+ /**
46
+ * Les surcharges dont le secret ne s'est pas ouvert.
47
+ *
48
+ * Vides en mémoire, elles doivent repartir chiffrées : sans cela, la
49
+ * sauvegarde suivante remplacerait par du blanc une valeur dont il ne
50
+ * manquait que la clé.
51
+ */
52
+ unreadableSecrets = /* @__PURE__ */ new Set();
53
+ /** Which vault each override was read from, until its project is known. */
54
+ roots = /* @__PURE__ */ new Map();
55
+ /**
56
+ * An override belongs to the project whose variable it answers.
57
+ *
58
+ * Nothing in an override says so — they are keyed by variable id alone — so
59
+ * the owning project is resolved through the environment that defines the
60
+ * variable. Overrides are never synced: they stay in the project's vault on
61
+ * this machine, and no other machine sees them.
62
+ *
63
+ * An override whose variable no longer exists (a deleted environment, a row
64
+ * left behind) has no project to belong to. It stays wherever it was read,
65
+ * falling back to the key's own directory — never dropped, since the variable
66
+ * may simply not be loaded yet.
67
+ */
68
+ async rootFor(variableId) {
69
+ const root = await environmentStore.rootOfVariable(variableId);
70
+ if (root) return root;
71
+ return this.roots.get(variableId) ?? dirname(await keyedFilePath(FILENAME));
72
+ }
73
+ /** Where earlier versions kept them: read once, rewritten to their vaults. */
74
+ getLegacyFilePath() {
75
+ return legacyMachineFilePath(FILENAME);
76
+ }
77
+ /** Les fichiers qui portent des surcharges : les coffres, et l'emplacement d'avant. */
78
+ async sourcePaths() {
79
+ const roots = await allVaultRoots();
80
+ return [
81
+ this.getLegacyFilePath(),
82
+ await keyedFilePath(FILENAME),
83
+ ...roots.map((root) => join(root, FILENAME))
84
+ ];
85
+ }
86
+ /**
87
+ * Charger, et recharger quand les fichiers ont bougé sous nos pieds.
88
+ *
89
+ * L'empreinte se prend **après** `ensureProjectsLoaded` : la liste des coffres
90
+ * en dépend, et une empreinte prise sur une liste incomplète ne ressemblerait
91
+ * à aucune des suivantes — le store se rechargerait à chaque lecture.
92
+ */
93
+ async load() {
94
+ await this.disk.load(async () => {
95
+ if (!getEncryptionKey()) return null;
96
+ await ensureProjectsLoaded();
97
+ const fingerprint = await fingerprintFiles(await this.sourcePaths());
98
+ if (this.loaded && fingerprint === this.fingerprint) return null;
99
+ const next = await this.readVaults();
100
+ return () => {
101
+ this.data = next.data;
102
+ this.diskEncryptedSlots = next.diskEncryptedSlots;
103
+ this.roots = next.roots;
104
+ this.unreadableSecrets = next.unreadableSecrets;
105
+ this.fingerprint = fingerprint;
106
+ this.loaded = true;
107
+ };
108
+ });
109
+ }
110
+ /**
111
+ * Read every vault, then the places older versions used, into fresh tables
112
+ * that `load` swaps in at once.
113
+ *
114
+ * Variable ids are unique, so merging the files cannot collide; a vault read
115
+ * later simply wins over a legacy copy of the same override.
116
+ */
117
+ async readVaults() {
118
+ const data = {};
119
+ const diskEncryptedSlots = {};
120
+ const roots = /* @__PURE__ */ new Map();
121
+ const unreadableSecrets = /* @__PURE__ */ new Set();
122
+ for (const path of await this.sourcePaths()) {
123
+ let parsed;
124
+ try {
125
+ parsed = JSON.parse(await readFile(path, "utf-8"));
126
+ } catch {
127
+ continue;
128
+ }
129
+ Object.assign(
130
+ diskEncryptedSlots,
131
+ extractEncryptedVariableSlots(parsed)
132
+ );
133
+ const decrypted = decryptVariableSlots(
134
+ parsed,
135
+ "environment-overrides",
136
+ (variableId) => unreadableSecrets.add(variableId),
137
+ vaultIdOfRoot(dirname(path))
138
+ );
139
+ for (const [id, override] of Object.entries(decrypted)) {
140
+ data[id] = { value: override.value };
141
+ roots.set(id, dirname(path));
142
+ }
143
+ }
144
+ return { data, diskEncryptedSlots, roots, unreadableSecrets };
145
+ }
146
+ save() {
147
+ return this.disk.save(() => this.doSave());
148
+ }
149
+ /**
150
+ * Write each vault that holds — or held — an override.
151
+ *
152
+ * A vault emptied by this save is still written, as an empty object: an
153
+ * override that moved to its project's vault must not survive in the one it
154
+ * came from.
155
+ */
156
+ async doSave() {
157
+ const byRoot = /* @__PURE__ */ new Map();
158
+ for (const root of this.roots.values()) byRoot.set(root, {});
159
+ for (const [variableId, override] of Object.entries(this.data)) {
160
+ const root = await this.rootFor(variableId);
161
+ this.roots.set(variableId, root);
162
+ const bucket = byRoot.get(root) ?? {};
163
+ bucket[variableId] = override;
164
+ byRoot.set(root, bucket);
165
+ }
166
+ for (const [root, overrides] of byRoot) {
167
+ const encrypted = this.keepUnreadableSecrets(encryptVariableSlots(
168
+ overrides,
169
+ this.diskEncryptedSlots,
170
+ vaultIdOfRoot(root)
171
+ ));
172
+ Object.assign(
173
+ this.diskEncryptedSlots,
174
+ extractEncryptedVariableSlots(encrypted)
175
+ );
176
+ await mkdir(root, { recursive: true });
177
+ const path = join(root, FILENAME);
178
+ const tmpPath = path + ".tmp";
179
+ await writeFile(tmpPath, JSON.stringify(encrypted, null, 2), "utf-8");
180
+ await renameWithRetry(tmpPath, path);
181
+ await chmod(path, 384);
182
+ }
183
+ }
184
+ /**
185
+ * Rendre au disque le chiffré d'une surcharge illisible, plutôt qu'un blanc.
186
+ *
187
+ * Pendant du garde-fou du store des environnements : tant que la valeur en
188
+ * mémoire est vide, c'est que personne n'a retouché la variable et que son
189
+ * chiffré fait toujours foi.
190
+ */
191
+ keepUnreadableSecrets(overrides) {
192
+ if (this.unreadableSecrets.size === 0) return overrides;
193
+ const result = { ...overrides };
194
+ for (const variableId of this.unreadableSecrets) {
195
+ const ciphertext = this.diskEncryptedSlots[variableId];
196
+ const override = result[variableId];
197
+ if (!ciphertext || !override || override.value.value) continue;
198
+ result[variableId] = { ...override, value: { ...override.value, value: ciphertext } };
199
+ }
200
+ return result;
201
+ }
202
+ async getOverride(variableId) {
203
+ await this.load();
204
+ return this.data[variableId] ?? null;
205
+ }
206
+ async setOverride(variableId, override) {
207
+ await this.load();
208
+ this.data[variableId] = { value: override.value };
209
+ await this.save();
210
+ }
211
+ async removeOverride(variableId) {
212
+ await this.load();
213
+ if (!this.data[variableId]) return;
214
+ delete this.data[variableId];
215
+ this.unreadableSecrets.delete(variableId);
216
+ await this.save();
217
+ }
218
+ async getAll() {
219
+ await this.load();
220
+ return { ...this.data };
221
+ }
222
+ async removeOverridesForVariables(variableIds) {
223
+ await this.load();
224
+ let changed = false;
225
+ for (const id of variableIds) {
226
+ if (this.data[id]) {
227
+ delete this.data[id];
228
+ this.unreadableSecrets.delete(id);
229
+ changed = true;
230
+ }
231
+ }
232
+ if (changed) await this.save();
233
+ }
234
+ };
235
+ var environmentOverridesStore = new EnvironmentOverridesStore();
236
+
237
+ // ../server/src/services/environment-resolver.ts
238
+ function interpolateValue(raw, envContext) {
239
+ return raw.replace(/\{\{environment\.([^}]+)\}\}/g, (match, key) => {
240
+ return envContext[key] !== void 0 ? envContext[key] : match;
241
+ });
242
+ }
243
+ function resolveVariable(variable, envContext) {
244
+ const slot = variable.value;
245
+ const finalValue = interpolateValue(slot.pre, envContext) + interpolateValue(slot.value, envContext) + interpolateValue(slot.post, envContext);
246
+ return { value: finalValue, isSecret: slot.isSecret };
247
+ }
248
+ function slotReferenceText(variable) {
249
+ const slot = variable.value;
250
+ return `${slot.pre}
251
+ ${slot.value}
252
+ ${slot.post}`;
253
+ }
254
+ var HIDDEN_VALUES_NOTICE = `Values shown as ${MASKED_VALUE} are secrets their author did not share with AI. The service does receive them: never treat such a key as missing, and never pass ${MASKED_VALUE} as its value.`;
255
+ function filterEnvForAi(resolved, sharedKeys) {
256
+ const secret = new Set(resolved.envSecrets);
257
+ const shared = new Set(sharedKeys);
258
+ const env = {};
259
+ const envSecrets = [];
260
+ const hiddenKeys = [];
261
+ for (const [key, value] of Object.entries(resolved.env)) {
262
+ const hidden = secret.has(key) && !shared.has(key);
263
+ env[key] = hidden ? MASKED_VALUE : value;
264
+ if (secret.has(key)) envSecrets.push(key);
265
+ if (hidden) hiddenKeys.push(key);
266
+ }
267
+ return {
268
+ env,
269
+ envSecrets,
270
+ hiddenKeys,
271
+ ...hiddenKeys.length > 0 ? { hiddenNotice: HIDDEN_VALUES_NOTICE } : {}
272
+ };
273
+ }
274
+ function describeVariables(environments, ctx) {
275
+ const details = [];
276
+ for (const environment of environments) {
277
+ for (const [variableId, variable] of Object.entries(environment.variables ?? {})) {
278
+ const slot = variable.value;
279
+ const isOverridden = ctx.overriddenVariableIds.has(variableId);
280
+ const isSecret = slot.isSecret || ctx.resolvedSecretKeys.has(variable.key);
281
+ const readableByAi = ctx.maskedKeys.has(variable.key) ? false : !isSecret || isSharedWithAi(slot);
282
+ details.push({
283
+ key: variable.key,
284
+ inService: ctx.serviceKeys.has(variable.key),
285
+ environmentId: environment.id,
286
+ environmentName: environment.name,
287
+ scope: environment.scope,
288
+ ...environment.scope === "service" && environment.reference ? { environmentServiceId: environment.reference } : {},
289
+ ...slot.description ? { description: slot.description } : {},
290
+ secret: isSecret,
291
+ readableByAi,
292
+ injectedIntoAi: slot.injectIntoAi,
293
+ required: slot.required,
294
+ overrideOnly: slot.overrideOnly,
295
+ overridden: isOverridden,
296
+ ...isOverridden && ctx.sharedValues[variable.key] !== void 0 ? { sharedValue: ctx.sharedValues[variable.key] } : {}
297
+ });
298
+ }
299
+ }
300
+ return details.sort((a, b) => a.key.localeCompare(b.key) || a.environmentName.localeCompare(b.environmentName));
301
+ }
302
+ function withOverriddenValue(variable, override) {
303
+ return {
304
+ ...variable,
305
+ value: {
306
+ ...variable.value,
307
+ value: override.value,
308
+ pre: override.pre,
309
+ post: override.post
310
+ }
311
+ };
312
+ }
313
+ var EnvironmentResolver = class {
314
+ async resolveForService(ctx, opts) {
315
+ if (!ctx.activeEnvironmentId) {
316
+ return { env: {}, envSecrets: [] };
317
+ }
318
+ const serviceEnv = await environmentStore.findServiceEnvironment(ctx.serviceId, ctx.activeEnvironmentId);
319
+ if (!serviceEnv) {
320
+ return this.resolveEnvironment(ctx.activeEnvironmentId, opts);
321
+ }
322
+ return this.resolveEnvironment(serviceEnv.id, opts);
323
+ }
324
+ /**
325
+ * `applyOverrides: false` rend ce que l'équipe partage, sans ce que ce poste
326
+ * a mis par-dessus : c'est la réponse à « qu'est-ce que ma surcharge
327
+ * remplace ». Le défaut reste `true` — tout le reste du produit veut la
328
+ * valeur avec laquelle le service tourne réellement.
329
+ */
330
+ async resolveEnvironment(environmentId, opts) {
331
+ const visited = /* @__PURE__ */ new Set();
332
+ const result = await this.resolveDag(environmentId, visited);
333
+ const overridesByKey = opts?.applyOverrides === false ? {} : await this.resolveOverridesByKey(environmentId);
334
+ for (const [varId, variable] of Object.entries(result.variables)) {
335
+ const override = overridesByKey[variable.key];
336
+ if (override) {
337
+ result.variables[varId] = withOverriddenValue(variable, override.variable.value);
338
+ }
339
+ }
340
+ const rawEnv = {};
341
+ for (const [_varId, variable] of Object.entries(result.variables)) {
342
+ const slot = variable.value;
343
+ rawEnv[variable.key] = slot.pre + slot.value + slot.post;
344
+ }
345
+ const { ctx: interpolationCtx, secretKeys: ctxSecretKeys } = await this.buildInterpolationContext(environmentId, rawEnv, result.parentEnv, result.parentSecretKeys, result.parentKeySources);
346
+ const secretKeys = this.collectSecretKeys(result.variables, ctxSecretKeys);
347
+ const env = {};
348
+ const envSecrets = [];
349
+ for (const [_varId, variable] of Object.entries(result.variables)) {
350
+ const { value, isSecret } = resolveVariable(variable, interpolationCtx);
351
+ env[variable.key] = value;
352
+ if (isSecret || secretKeys.has(variable.key)) {
353
+ envSecrets.push(variable.key);
354
+ }
355
+ }
356
+ return { env, envSecrets };
357
+ }
358
+ /**
359
+ * Resolve an environment (with inheritance) and return only the variables
360
+ * flagged `injectIntoAi`, as a flat KEY→value dict ready to be injected into
361
+ * the process environment of an AI agent spawn.
362
+ */
363
+ async resolveAiInjectedEnv(environmentId) {
364
+ if (!environmentId) return {};
365
+ const visited = /* @__PURE__ */ new Set();
366
+ const result = await this.resolveDag(environmentId, visited);
367
+ const overridesByKey = await this.resolveOverridesByKey(environmentId);
368
+ for (const [varId, variable] of Object.entries(result.variables)) {
369
+ const override = overridesByKey[variable.key];
370
+ if (override) {
371
+ result.variables[varId] = withOverriddenValue(variable, override.variable.value);
372
+ }
373
+ }
374
+ const rawEnv = {};
375
+ for (const variable of Object.values(result.variables)) {
376
+ const slot = variable.value;
377
+ rawEnv[variable.key] = slot.pre + slot.value + slot.post;
378
+ }
379
+ const { ctx: interpolationCtx } = await this.buildInterpolationContext(
380
+ environmentId,
381
+ rawEnv,
382
+ result.parentEnv,
383
+ result.parentSecretKeys,
384
+ result.parentKeySources
385
+ );
386
+ const injected = {};
387
+ for (const variable of Object.values(result.variables)) {
388
+ if (!variable.value.injectIntoAi) continue;
389
+ const { value } = resolveVariable(variable, interpolationCtx);
390
+ injected[variable.key] = value;
391
+ }
392
+ return injected;
393
+ }
394
+ /**
395
+ * Les variables qu'il faut remplir avant qu'un service de cet environnement
396
+ * puisse démarrer.
397
+ *
398
+ * Deux motifs, et ils ne se mesurent pas au même endroit :
399
+ *
400
+ * - `required` porte sur la valeur **finale**, interpolation et surcharge
401
+ * comprises : une variable obligatoire dont la valeur ne tient qu'à une
402
+ * référence morte est aussi vide qu'une case blanche.
403
+ * - `overrideOnly` porte sur l'**existence d'une surcharge machine**. Elle
404
+ * n'a par construction pas de valeur partagée ; ce qui manque n'est pas un
405
+ * contenu, c'est la réponse de ce poste-ci.
406
+ *
407
+ * Les drapeaux se lisent sur la définition, jamais sur le slot résolu : une
408
+ * surcharge remplace le slot entier et ne porte aucun drapeau — les y lire
409
+ * rendrait toute variable surchargée silencieusement facultative.
410
+ */
411
+ async findMissingVariables(environmentId) {
412
+ if (!environmentId) return [];
413
+ const [{ env }, definitions, overridesByKey] = await Promise.all([
414
+ this.resolveEnvironment(environmentId),
415
+ this.resolveDag(environmentId, /* @__PURE__ */ new Set()),
416
+ this.resolveOverridesByKey(environmentId)
417
+ ]);
418
+ const missing = [];
419
+ for (const [variableId, variable] of Object.entries(definitions.variables)) {
420
+ const slot = variable.value;
421
+ const source = definitions.sources[variableId];
422
+ const base = {
423
+ variableId,
424
+ key: variable.key,
425
+ description: slot.description,
426
+ isSecret: slot.isSecret,
427
+ environmentId: source?.environmentId ?? environmentId,
428
+ environmentName: source?.environmentName ?? ""
429
+ };
430
+ if (slot.overrideOnly && !overridesByKey[variable.key]) {
431
+ missing.push({ ...base, reason: "overrideOnly" });
432
+ continue;
433
+ }
434
+ if (slot.required && (env[variable.key] ?? "") === "") {
435
+ missing.push({ ...base, reason: "required" });
436
+ }
437
+ }
438
+ return missing;
439
+ }
440
+ /**
441
+ * Tout ce qu'il reste à remplir sous l'environnement courant.
442
+ *
443
+ * Deux périmètres, et il faut les deux :
444
+ *
445
+ * 1. **L'environnement courant lui-même**, héritage compris —
446
+ * `findMissingVariables` remonte ses `parentIds`. C'est là que vivent les
447
+ * variables globales du projet, et c'est la première branche balayée.
448
+ * 2. **Les environnements de service qui s'activent avec lui**
449
+ * (`activateOn`). Ceux-là ne sont pas des ancêtres du global : ils en
450
+ * héritent, dans l'autre sens. Ne pas y descendre revenait à ne rien
451
+ * réclamer d'un service jusqu'à ce qu'on essaie de le démarrer.
452
+ *
453
+ * Dédoublonné par identifiant de variable : une variable du global remonte
454
+ * dans chaque branche de service qui en hérite, et l'assistant ne doit pas
455
+ * demander deux fois la même chose.
456
+ */
457
+ async findMissingForActiveEnvironment(globalEnvId) {
458
+ if (!globalEnvId) return [];
459
+ const serviceEnvs = await environmentStore.listByActivateOn(globalEnvId);
460
+ const branches = await Promise.all([
461
+ this.findMissingVariables(globalEnvId),
462
+ ...serviceEnvs.map((env) => this.findMissingVariables(env.id))
463
+ ]);
464
+ const seen = /* @__PURE__ */ new Set();
465
+ const missing = [];
466
+ for (const branch of branches) {
467
+ for (const item of branch) {
468
+ if (seen.has(item.variableId)) continue;
469
+ seen.add(item.variableId);
470
+ missing.push(item);
471
+ }
472
+ }
473
+ return missing;
474
+ }
475
+ /**
476
+ * Les clés que leur auteur a partagées avec les IA, héritage compris.
477
+ *
478
+ * Le partage se lit sur la **définition**, et seulement là : une surcharge
479
+ * machine ne dit que la valeur de ce poste (`withOverriddenValue`). Il n'y a
480
+ * donc qu'un endroit où ce drapeau existe, et rien à réconcilier.
481
+ *
482
+ * Des clés, pas des valeurs : la valeur rendue reste celle que le service
483
+ * reçoit, surcharges et interpolation comprises.
484
+ */
485
+ async resolveAiSharedKeys(environmentId) {
486
+ if (!environmentId) return /* @__PURE__ */ new Set();
487
+ const result = await this.resolveDag(environmentId, /* @__PURE__ */ new Set());
488
+ const keys = /* @__PURE__ */ new Set();
489
+ for (const variable of Object.values(result.variables)) {
490
+ if (isSharedWithAi(variable.value)) keys.add(variable.key);
491
+ }
492
+ return keys;
493
+ }
494
+ /**
495
+ * Idem, pour ce qu'un service verra réellement : son environnement dédié
496
+ * quand il en a un, l'environnement global sinon — la règle de sélection de
497
+ * `resolveForService`.
498
+ */
499
+ async resolveAiSharedKeysForService(ctx) {
500
+ if (!ctx.activeEnvironmentId) return /* @__PURE__ */ new Set();
501
+ const serviceEnv = await environmentStore.findServiceEnvironment(ctx.serviceId, ctx.activeEnvironmentId);
502
+ return this.resolveAiSharedKeys(serviceEnv ? serviceEnv.id : ctx.activeEnvironmentId);
503
+ }
504
+ /**
505
+ * Idem, pour ce qu'un service verra réellement : son environnement dédié
506
+ * quand il en a un, l'environnement global sinon. Miroir de
507
+ * `resolveForService`, dont il partage la règle de sélection.
508
+ */
509
+ async findMissingForService(ctx) {
510
+ if (!ctx.activeEnvironmentId) return [];
511
+ const serviceEnv = await environmentStore.findServiceEnvironment(ctx.serviceId, ctx.activeEnvironmentId);
512
+ return this.findMissingVariables(serviceEnv ? serviceEnv.id : ctx.activeEnvironmentId);
513
+ }
514
+ async resolveEnvironmentWithSources(environmentId) {
515
+ const visited = /* @__PURE__ */ new Set();
516
+ const result = await this.resolveDag(environmentId, visited);
517
+ const overridesByKey = await this.resolveOverridesByKey(environmentId);
518
+ for (const [varId, variable] of Object.entries(result.variables)) {
519
+ const override = overridesByKey[variable.key];
520
+ if (override) {
521
+ result.variables[varId] = withOverriddenValue(variable, override.variable.value);
522
+ result.sources[varId] = {
523
+ ...result.sources[varId],
524
+ overridden: true,
525
+ ...override.source ? { overriddenBy: override.source } : {}
526
+ };
527
+ }
528
+ }
529
+ const rawEnv = {};
530
+ for (const [_varId, variable] of Object.entries(result.variables)) {
531
+ const slot = variable.value;
532
+ rawEnv[variable.key] = slot.pre + slot.value + slot.post;
533
+ }
534
+ const { ctx: interpolationCtx, secretKeys: ctxSecretKeys, keySources } = await this.buildInterpolationContext(environmentId, rawEnv, result.parentEnv, result.parentSecretKeys, result.parentKeySources);
535
+ const secretKeys = this.collectSecretKeys(result.variables, ctxSecretKeys);
536
+ const env = {};
537
+ const envSecrets = [];
538
+ for (const [_varId, variable] of Object.entries(result.variables)) {
539
+ const { value, isSecret } = resolveVariable(variable, interpolationCtx);
540
+ env[variable.key] = value;
541
+ if (isSecret || secretKeys.has(variable.key)) {
542
+ envSecrets.push(variable.key);
543
+ }
544
+ }
545
+ const refPattern = /^\{\{environment\.([^}]+)\}\}$/;
546
+ for (const [varId, variable] of Object.entries(result.variables)) {
547
+ const match = variable.value.value.match(refPattern);
548
+ if (match) {
549
+ const refSource = keySources[match[1]];
550
+ if (refSource && result.sources[varId]?.environmentId !== refSource.environmentId) {
551
+ result.sources[varId] = {
552
+ ...result.sources[varId],
553
+ resolvedFrom: refSource
554
+ };
555
+ }
556
+ }
557
+ }
558
+ return {
559
+ variables: result.variables,
560
+ env,
561
+ envSecrets,
562
+ sources: result.sources
563
+ };
564
+ }
565
+ /** Check if a raw value string interpolates any key that is secret in the context */
566
+ /**
567
+ * Toutes les clés dont la valeur est, directement ou par interpolation, un
568
+ * secret.
569
+ *
570
+ * Le contexte d'interpolation ne connaît que les secrets *hérités* : les
571
+ * secrets définis dans le même environnement n'y figurent pas, si bien qu'un
572
+ * `AUTH='Bearer {{environment.TOKEN}}'` voisin de son propre `TOKEN` secret
573
+ * ressortait non marqué — et donc non masqué par toute la chaîne en aval.
574
+ *
575
+ * On part des secrets hérités plus ceux déclarés ici, puis on propage
576
+ * jusqu'au point fixe : une valeur qui référence une clé secrète devient
577
+ * secrète à son tour, y compris en chaîne (A secret → B cite A → C cite B).
578
+ */
579
+ collectSecretKeys(variables, parentSecretKeys) {
580
+ const secretKeys = new Set(parentSecretKeys);
581
+ for (const variable of Object.values(variables)) {
582
+ if (variable.value.isSecret) secretKeys.add(variable.key);
583
+ }
584
+ let changed = true;
585
+ while (changed) {
586
+ changed = false;
587
+ for (const variable of Object.values(variables)) {
588
+ if (secretKeys.has(variable.key)) continue;
589
+ if (this.interpolatesSecretKey(slotReferenceText(variable), secretKeys)) {
590
+ secretKeys.add(variable.key);
591
+ changed = true;
592
+ }
593
+ }
594
+ }
595
+ return secretKeys;
596
+ }
597
+ interpolatesSecretKey(rawValue, ctxSecretKeys) {
598
+ const refs = [...rawValue.matchAll(/\{\{environment\.([^}]+)\}\}/g)].map((m) => m[1]);
599
+ return refs.some((ref) => ctxSecretKeys.has(ref));
600
+ }
601
+ /**
602
+ * Build the interpolation context for an environment.
603
+ *
604
+ * For inheriting envs (has parents): start from parent concrete values,
605
+ * then overlay with current concrete values. This ensures that
606
+ * {{environment.KEY}} resolves against the parent's value when the child
607
+ * redefines KEY as an interpolation reference.
608
+ *
609
+ * For isolated service envs (scope=service, activateOn set, no parents):
610
+ * the global env is resolved and used as fallback.
611
+ */
612
+ async buildInterpolationContext(environmentId, rawEnv, parentEnv, parentSecretKeys, parentKeySources) {
613
+ const environment = await environmentStore.get(environmentId);
614
+ if (environment && environment.scope === "service" && environment.activateOn && (!environment.parentIds || environment.parentIds.length === 0)) {
615
+ const globalResolved = await this.resolveEnvironmentWithSources(environment.activateOn);
616
+ const secretKeys = new Set(globalResolved.envSecrets);
617
+ const keySources = {};
618
+ for (const [varId, variable] of Object.entries(globalResolved.variables)) {
619
+ const source = globalResolved.sources[varId];
620
+ if (source) {
621
+ keySources[variable.key] = { environmentId: source.environmentId, environmentName: source.environmentName };
622
+ }
623
+ }
624
+ const ctx2 = { ...globalResolved.env };
625
+ for (const [key, value] of Object.entries(rawEnv)) {
626
+ if (!/\{\{environment\.[^}]+\}\}/.test(value)) {
627
+ ctx2[key] = value;
628
+ }
629
+ }
630
+ return { ctx: ctx2, secretKeys, keySources };
631
+ }
632
+ const ctx = { ...parentEnv };
633
+ for (const [key, value] of Object.entries(rawEnv)) {
634
+ if (!/\{\{environment\.[^}]+\}\}/.test(value)) {
635
+ ctx[key] = value;
636
+ }
637
+ }
638
+ return { ctx, secretKeys: parentSecretKeys, keySources: parentKeySources };
639
+ }
640
+ /**
641
+ * For service-scoped envs, compute effective parentIds by also including
642
+ * the service-scoped envs of ancestor global environments.
643
+ *
644
+ * Example: "Server (test)" has parentIds=[test-global]. test-global has
645
+ * parentIds=[Local-global]. This method adds "Server (Local)" to the
646
+ * effective parents so service-specific variables from ancestor envs
647
+ * are inherited correctly.
648
+ */
649
+ async getEffectiveParentIds(environment) {
650
+ if (environment.scope !== "service" || !environment.reference || !environment.activateOn) {
651
+ return environment.parentIds;
652
+ }
653
+ const additionalIds = [];
654
+ for (const parentId of environment.parentIds) {
655
+ const parentEnv = await environmentStore.get(parentId);
656
+ if (!parentEnv || parentEnv.scope !== "global") continue;
657
+ for (const grandparentGlobalId of parentEnv.parentIds) {
658
+ const ancestorServiceEnv = await environmentStore.findServiceEnvironment(environment.reference, grandparentGlobalId);
659
+ if (ancestorServiceEnv && !environment.parentIds.includes(ancestorServiceEnv.id)) {
660
+ additionalIds.push(ancestorServiceEnv.id);
661
+ }
662
+ }
663
+ }
664
+ if (additionalIds.length === 0) return environment.parentIds;
665
+ return [...environment.parentIds, ...additionalIds];
666
+ }
667
+ /**
668
+ * Project an environment's variables onto their overrides: keep only the
669
+ * variables that have one, and swap in the override's value slot. The key
670
+ * always comes from the definition.
671
+ *
672
+ * Feeding this projection back through `resolveDag` resolves the override
673
+ * chain with the exact same inheritance and dedup-by-key rules as the value
674
+ * chain — so an override set on a parent env is no longer swallowed when a
675
+ * child (or a service env) redeclares the same key.
676
+ */
677
+ projectOverrides(variables, overrides) {
678
+ const projected = {};
679
+ for (const [varId, variable] of Object.entries(variables)) {
680
+ const override = overrides[varId];
681
+ if (override) {
682
+ projected[varId] = { key: variable.key, value: override.value };
683
+ }
684
+ }
685
+ return projected;
686
+ }
687
+ /**
688
+ * Resolve the override chain independently of the value chain and return the
689
+ * winning override per variable key (empty when nothing is overridden).
690
+ */
691
+ async resolveOverridesByKey(environmentId) {
692
+ const allOverrides = await environmentOverridesStore.getAll();
693
+ if (Object.keys(allOverrides).length === 0) return {};
694
+ const result = await this.resolveDag(
695
+ environmentId,
696
+ /* @__PURE__ */ new Set(),
697
+ (variables) => this.projectOverrides(variables, allOverrides)
698
+ );
699
+ const byKey = {};
700
+ for (const [varId, variable] of Object.entries(result.variables)) {
701
+ const source = result.sources[varId];
702
+ byKey[variable.key] = {
703
+ variable,
704
+ ...source ? { source: { environmentId: source.environmentId, environmentName: source.environmentName } } : {}
705
+ };
706
+ }
707
+ return byKey;
708
+ }
709
+ async resolveDag(environmentId, visited, project) {
710
+ if (visited.has(environmentId)) {
711
+ throw new Error(`Circular dependency detected in environment inheritance for ${environmentId}`);
712
+ }
713
+ const environment = await environmentStore.get(environmentId);
714
+ if (!environment) {
715
+ throw new Error(`Environment "${environmentId}" not found`);
716
+ }
717
+ visited.add(environmentId);
718
+ const effectiveParentIds = await this.getEffectiveParentIds(environment);
719
+ const parentResults = [];
720
+ for (const parentId of effectiveParentIds) {
721
+ const parentVisited = new Set(visited);
722
+ const parentResult = await this.resolveDag(parentId, parentVisited, project);
723
+ parentResults.push(parentResult);
724
+ }
725
+ const mergedVariables = {};
726
+ const sources = {};
727
+ for (const result of parentResults) {
728
+ for (const [varId, variable] of Object.entries(result.variables)) {
729
+ for (const [existingId, existingVar] of Object.entries(mergedVariables)) {
730
+ if (existingVar.key === variable.key && existingId !== varId) {
731
+ delete mergedVariables[existingId];
732
+ delete sources[existingId];
733
+ }
734
+ }
735
+ mergedVariables[varId] = variable;
736
+ sources[varId] = result.sources[varId] ?? sources[varId];
737
+ }
738
+ }
739
+ const parentEnv = {};
740
+ const parentSecretKeys = /* @__PURE__ */ new Set();
741
+ const parentKeySources = {};
742
+ for (const [varId, variable] of Object.entries(mergedVariables)) {
743
+ const slot = variable.value;
744
+ parentEnv[variable.key] = slot.pre + slot.value + slot.post;
745
+ if (slot.isSecret) {
746
+ parentSecretKeys.add(variable.key);
747
+ }
748
+ const source = sources[varId];
749
+ if (source) {
750
+ parentKeySources[variable.key] = { environmentId: source.environmentId, environmentName: source.environmentName };
751
+ }
752
+ }
753
+ const isInterpRef = (v) => /\{\{environment\.[^}]+\}\}/.test(v);
754
+ for (const result of parentResults) {
755
+ for (const [key, value] of Object.entries(result.parentEnv)) {
756
+ const existingIsRef = key in parentEnv && isInterpRef(parentEnv[key]);
757
+ const newIsConcrete = !isInterpRef(value);
758
+ if (!(key in parentEnv) || existingIsRef && newIsConcrete) {
759
+ parentEnv[key] = value;
760
+ }
761
+ }
762
+ for (const key of result.parentSecretKeys) {
763
+ parentSecretKeys.add(key);
764
+ }
765
+ for (const [key, source] of Object.entries(result.parentKeySources)) {
766
+ if (!(key in parentKeySources)) {
767
+ parentKeySources[key] = source;
768
+ }
769
+ }
770
+ }
771
+ for (const key of this.collectSecretKeys(mergedVariables, parentSecretKeys)) {
772
+ parentSecretKeys.add(key);
773
+ }
774
+ const ownVariables = project ? project(environment.variables) : environment.variables;
775
+ for (const [varId, variable] of Object.entries(ownVariables)) {
776
+ let wasInherited = varId in mergedVariables;
777
+ for (const [existingId, existingVar] of Object.entries(mergedVariables)) {
778
+ if (existingVar.key === variable.key && existingId !== varId) {
779
+ delete mergedVariables[existingId];
780
+ delete sources[existingId];
781
+ wasInherited = true;
782
+ }
783
+ }
784
+ mergedVariables[varId] = variable;
785
+ sources[varId] = {
786
+ environmentId: environment.id,
787
+ environmentName: environment.name,
788
+ overridden: wasInherited
789
+ };
790
+ }
791
+ return {
792
+ variables: mergedVariables,
793
+ sources,
794
+ parentEnv,
795
+ parentSecretKeys,
796
+ parentKeySources
797
+ };
798
+ }
799
+ };
800
+ var environmentResolver = new EnvironmentResolver();
801
+
802
+ export {
803
+ environmentOverridesStore,
804
+ HIDDEN_VALUES_NOTICE,
805
+ filterEnvForAi,
806
+ describeVariables,
807
+ environmentResolver
808
+ };
809
+ //# sourceMappingURL=chunk-WDHLEO5S.js.map