@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 @@
1
+ {"version":3,"sources":["../../server/src/services/store-disk-coordinator.ts","../../server/src/services/project-key.ts","../../server/src/services/vault-registry.ts","../../server/src/services/local-removals.ts","../../server/src/services/environment-store.ts","../../server/src/utils/encryption-key.ts","../../server/src/services/vault-conflicts.ts","../../server/src/services/crypto-helpers.ts"],"sourcesContent":["import { AsyncLocalStorage } from 'node:async_hooks';\n\n/**\n * Recharger un store depuis le disque sans jamais perdre ce qu'il contient.\n *\n * Plusieurs Runeya partagent la racine machine : un store relit ses fichiers\n * quand ils ont bougé. Relire en vidant la mémoire d'abord laissait une fenêtre\n * où une sauvegarde concurrente écrivait un état à moitié rempli, et effaçait\n * du disque ce qui n'était pas encore relu — c'est ce qui a vidé des coffres le\n * 12 septembre. Trois règles tiennent ici, pour tous les stores :\n *\n * - un rechargement lit dans des structures neuves et ne les substitue qu'une\n * fois complètes ;\n * - un seul rechargement à la fois, et jamais pendant une écriture en file ;\n * - une sauvegarde partie pendant la lecture la rend caduque : on relit.\n *\n * Les écritures passent en file, chacune écrivant la mémoire au moment où vient\n * son tour : lancées ensemble, la plus ancienne pouvait finir la dernière et\n * recouvrir la plus récente.\n */\nconst insideReload = new AsyncLocalStorage<Set<StoreDiskCoordinator>>();\n\nexport class StoreDiskCoordinator {\n private reloading: Promise<void> | null = null;\n private saves = 0;\n private queue: Promise<void> = Promise.resolve();\n\n /**\n * `read` rend de quoi substituer le nouvel état, ou `null` s'il n'y a rien à\n * relire. La substitution doit être synchrone : c'est ce qui la rend atomique.\n */\n load(read: () => Promise<(() => void) | null>): Promise<void> {\n // Appelé depuis une lecture en cours — la sienne, ou celle d'un store qui\n // en interroge un autre : attendre un rechargement déjà lancé peut boucler.\n // Deux rechargements partis par deux portes s'attendaient l'un l'autre\n // (environnements → projets → environnements). L'appel imbriqué travaille\n // sur la mémoire actuelle.\n const inside = insideReload.getStore();\n if (inside && (inside.has(this) || this.reloading)) return Promise.resolve();\n this.reloading ??= this.reload(read).finally(() => { this.reloading = null; });\n return this.reloading;\n }\n\n private async reload(read: () => Promise<(() => void) | null>): Promise<void> {\n for (;;) {\n await this.queue;\n const savesBefore = this.saves;\n const outer = insideReload.getStore() ?? new Set<StoreDiskCoordinator>();\n const commit = await insideReload.run(new Set([...outer, this]), read);\n if (!commit) return;\n if (this.saves !== savesBefore) continue;\n commit();\n return;\n }\n }\n\n save(write: () => Promise<void>): Promise<void> {\n this.saves += 1;\n const run = this.queue.then(write);\n this.queue = run.catch(() => {});\n return run;\n }\n}\n","/**\n * L'identité d'un projet, telle que le disque et le cloud la connaissent.\n *\n * Un `projectId` seul ne désigne rien : le même id peut exister dans plusieurs\n * organisations — c'est ce qui arrive dès qu'un projet est suivi par une org\n * puis par une autre, l'entrée précédente restant dans le doc de la première.\n * Ce qui place un projet sur disque est déjà le couple (`vaultFor`), donc c'est\n * le couple qui doit l'identifier partout au-dessus.\n */\n\nexport interface ProjectRef {\n id: string;\n orgId?: string | null;\n}\n\n/** Deux projets ont la même clé exactement quand ils sont le même projet. */\nexport function projectKey(ref: ProjectRef): string {\n return `${ref.orgId ?? 'local'}:${ref.id}`;\n}\n\n/**\n * Un `projectId` a désigné un projet à lui seul, et le désigne encore dans tout\n * ce qu'un projet contient : un environnement, une conversation, un override ne\n * nomment que leur projet. Tant que ces formats n'ont pas migré, la résolution\n * par id seul doit rester possible — mais elle doit échouer bruyamment quand\n * plusieurs projets répondent, plutôt que d'en élire un au hasard.\n */\nexport class AmbiguousProjectError extends Error {\n readonly code = 'AMBIGUOUS_PROJECT_ID';\n\n constructor(readonly projectId: string, readonly orgIds: (string | null)[]) {\n const where = orgIds.map((o) => o ?? 'local').join(', ');\n super(\n `Project id ${projectId} exists in several organizations (${where}). ` +\n 'Name the organization alongside the project id.',\n );\n this.name = 'AmbiguousProjectError';\n }\n}\n","import { localVaultRoot } from './vault-resolver.js';\nimport { projectKey, AmbiguousProjectError, type ProjectRef } from './project-key.js';\n\n/**\n * Which vault each entity belongs to.\n *\n * Projects know where they live — `vaultFor` derives it from their `orgId` —\n * but their contents do not: a service carries no project id (ownership lives\n * in `project.serviceIds`), and an environment only names its project. Rather\n * than have every store reach into the project store — and import its way into\n * a cycle — the project store publishes what it knows here, and the content\n * stores read it.\n *\n * Everything is keyed by the (organization, project) couple, because that is\n * what identifies a project: the same project id can exist in two organizations\n * and point at two different vaults. Contained entities still name their project\n * by id alone, so `rootOfProject` resolves that id — and refuses to guess when\n * more than one project answers to it.\n *\n * Anything unknown resolves to the local vault. That is the honest default: an\n * entity nobody claims belongs to the directory the server was launched in,\n * which is exactly where it used to live before vaults existed.\n */\n\n/** Set by the project store, so content stores can make sure it has loaded. */\nlet loadProjects: (() => Promise<void>) | null = null;\n\n/** key = `${orgId ?? 'local'}:${projectId}` */\nconst projectRoots = new Map<string, string>();\n/** The refs behind each bare project id, to spot an id that answers twice. */\nconst projectRefs = new Map<string, ProjectRef>();\n/**\n * Quels projets revendiquent chaque service.\n *\n * Un ensemble, pas un propriétaire unique : deux organisations portant le même\n * projet déclarent le même service, et retenir le dernier faisait écrire ce\n * service dans le coffre de l'autre — vidant celui d'où il venait.\n */\nconst serviceOwners = new Map<string, Set<string>>();\n\nexport function registerProjectLoader(load: () => Promise<void>): void {\n loadProjects = load;\n}\n\n/**\n * Make sure the project store has read the disk.\n *\n * Content stores call this before their own load: until projects are known,\n * every id would resolve to the local vault and cloud files would be missed.\n */\nexport async function ensureProjectsLoaded(): Promise<void> {\n await loadProjects?.();\n}\n\nexport function setProjectVault(ref: ProjectRef, root: string): void {\n const key = projectKey(ref);\n projectRoots.set(key, root);\n projectRefs.set(key, { id: ref.id, orgId: ref.orgId ?? null });\n}\n\nexport function forgetProject(ref: ProjectRef): void {\n const key = projectKey(ref);\n projectRoots.delete(key);\n projectRefs.delete(key);\n for (const [serviceId, owners] of serviceOwners) {\n owners.delete(key);\n if (owners.size === 0) serviceOwners.delete(serviceId);\n }\n}\n\n/** Record which services a project owns, replacing what it owned before. */\nexport function setProjectServices(ref: ProjectRef, serviceIds: string[]): void {\n const key = projectKey(ref);\n for (const [serviceId, owners] of serviceOwners) {\n if (!serviceIds.includes(serviceId)) {\n owners.delete(key);\n if (owners.size === 0) serviceOwners.delete(serviceId);\n }\n }\n for (const serviceId of serviceIds) {\n const owners = serviceOwners.get(serviceId) ?? new Set<string>();\n owners.add(key);\n serviceOwners.set(serviceId, owners);\n }\n}\n\n/** Where a project lives, when its organization is known. */\nexport function rootOfProjectRef(ref: ProjectRef): string {\n return projectRoots.get(projectKey(ref)) ?? localVaultRoot();\n}\n\n/** Every project registered under a bare id — one, usually. */\nexport function refsOfProjectId(projectId: string): ProjectRef[] {\n const matches: ProjectRef[] = [];\n for (const ref of projectRefs.values()) {\n if (ref.id === projectId) matches.push(ref);\n }\n return matches;\n}\n\n/**\n * Where a project lives, from its id alone.\n *\n * Throws when the id answers for two projects: picking one would write a\n * project's services into another organization's vault, which is precisely the\n * silent corruption the composite key exists to prevent.\n */\nexport function rootOfProject(projectId: string): string {\n return rootOfProjectAmong(projectId, null);\n}\n\n/**\n * Where a project lives, from its id and the vault an entity came from.\n *\n * Everything a project contains — an environment, an override, a conversation —\n * names its project by id alone, but sits inside that project's vault. When the\n * id answers for two projects, that directory says which one: it is the couple,\n * written down by the layout. Without such a hint, an ambiguous id still throws\n * rather than electing one of the two.\n */\nexport function rootOfProjectAmong(projectId: string, hint: string | null): string {\n const matches = refsOfProjectId(projectId);\n if (matches.length > 1) {\n const known = matches.map((ref) => rootOfProjectRef(ref));\n if (hint && known.includes(hint)) return hint;\n throw new AmbiguousProjectError(projectId, matches.map((r) => r.orgId ?? null));\n }\n // Aucun projet connu sous cet id : l'entité reste là où elle a été lue. La\n // renvoyer au coffre de lancement la sortirait de son organisation — ce qui\n // arrive précisément quand les projets ne sont pas encore chargés.\n const [ref] = matches;\n return ref ? rootOfProjectRef(ref) : (hint ?? localVaultRoot());\n}\n\n/** The couple behind a project id, disambiguated by the vault an entity came from. */\nexport function refOfProjectAmong(projectId: string, hint: string | null): ProjectRef {\n const matches = refsOfProjectId(projectId);\n if (matches.length > 1) {\n const found = hint ? matches.find((ref) => rootOfProjectRef(ref) === hint) : undefined;\n if (found) return found;\n throw new AmbiguousProjectError(projectId, matches.map((r) => r.orgId ?? null));\n }\n return matches[0] ?? { id: projectId, orgId: null };\n}\n\nexport function rootOfService(serviceId: string, hint: string | null = null): string {\n const owners = serviceOwners.get(serviceId);\n if (!owners || owners.size === 0) return hint ?? localVaultRoot();\n const roots = Array.from(owners, (key) => projectRoots.get(key)).filter((r): r is string => !!r);\n // Revendiqué par plusieurs projets — le même projet dans deux organisations :\n // le coffre d'où le service a été lu tranche, sinon le premier connu.\n if (hint && roots.includes(hint)) return hint;\n return roots[0] ?? hint ?? localVaultRoot();\n}\n\n/**\n * Every vault holding data, the local one first.\n *\n * Stores read all of them and write back each one they touched, so an entity\n * that moves between vaults never lingers in the one it came from.\n */\nexport function knownRoots(): string[] {\n const roots = new Set<string>([localVaultRoot()]);\n for (const root of projectRoots.values()) roots.add(root);\n return Array.from(roots);\n}\n\n/** Test seam: drop everything the registry learned. */\nexport function resetVaultRegistry(): void {\n projectRoots.clear();\n projectRefs.clear();\n serviceOwners.clear();\n loadProjects = null;\n}\n","/**\n * Ce que cette machine a retiré, par un geste explicite.\n *\n * La synchronisation ne déduit jamais une suppression d'une absence : une\n * entité absente d'ici peut n'avoir pas été lue (coffre écarté, scellé, copie\n * pas encore descendue), et la retirer du document l'effaçait pour toute\n * l'organisation. Seuls les retraits inscrits ici partent au cloud.\n *\n * Deux registres :\n * - les entités supprimées (services, environnements, parseurs) ;\n * - les liens défaits entre un projet et ses services ou environnements — un\n * projet repoussé garde sinon les ids que le document connaît et pas nous.\n *\n * En mémoire : un redémarrage avant l'envoi fait réapparaître l'entité, ce qui\n * se rattrape ; l'inverse — perdre une donnée — ne se rattrape pas.\n */\n\nexport type RemovableKind = 'services' | 'environments' | 'logParsers';\nexport type ProjectLinkField = 'serviceIds' | 'environmentIds';\n\nconst removed = new Map<RemovableKind, Set<string>>();\nconst detached = new Map<string, Set<string>>();\n\nconst linkKey = (projectId: string, field: ProjectLinkField): string => `${projectId}:${field}`;\n\nexport function recordLocalRemoval(kind: RemovableKind, id: string): void {\n const ids = removed.get(kind) ?? new Set<string>();\n ids.add(id);\n removed.set(kind, ids);\n}\n\nexport function isLocallyRemoved(kind: RemovableKind, id: string): boolean {\n return removed.get(kind)?.has(id) ?? false;\n}\n\nexport function clearLocalRemoval(kind: RemovableKind, id: string): void {\n removed.get(kind)?.delete(id);\n}\n\n/** Inscrire les ids qu'une nouvelle liste retire de l'ancienne. */\nexport function recordDetached(\n projectId: string, field: ProjectLinkField, before: readonly string[], after: readonly string[],\n): void {\n const kept = new Set(after);\n const gone = before.filter((id) => !kept.has(id));\n if (gone.length === 0) return;\n const key = linkKey(projectId, field);\n const ids = detached.get(key) ?? new Set<string>();\n for (const id of gone) ids.add(id);\n detached.set(key, ids);\n}\n\nexport function isDetached(projectId: string, field: ProjectLinkField, id: string): boolean {\n return detached.get(linkKey(projectId, field))?.has(id) ?? false;\n}\n\nexport function clearDetached(projectId: string, field: ProjectLinkField): void {\n detached.delete(linkKey(projectId, field));\n}\n\n/** Test seam. */\nexport function resetLocalRemovals(): void {\n removed.clear();\n detached.clear();\n}\n","import { randomUUID } from 'node:crypto';\nimport { readFile, rm } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { getEncryptionKey } from '../utils/encryption-key.js';\nimport { allVaultRoots, localVaultRoot, vaultFor, vaultIdOfRoot } from './vault-resolver.js';\nimport { rememberFile, hasChangedSinceRead, wasRead, fingerprintFiles } from './disk-freshness.js';\nimport { rootOfProjectAmong, refOfProjectAmong, ensureProjectsLoaded } from './vault-registry.js';\nimport { markVaultConflict, isVaultConflicted, isVaultClash } from './vault-conflicts.js';\nimport { recordLocalRemoval } from './local-removals.js';\nimport { atomicWriteSecure } from './run-store-utils.js';\nimport { StoreDiskCoordinator } from './store-disk-coordinator.js';\nimport type { ProjectRef } from './project-key.js';\nimport {\n encryptVariableSlots,\n decryptVariableSlots,\n extractEncryptedVariableSlots,\n} from './crypto-helpers.js';\nimport type { Environment, CreateEnvironment, UpdateEnvironment, VariableSlot } from '@runeya/packages-shared';\nimport { CreateEnvironmentSchema, EnvironmentSchema } from '@runeya/packages-shared';\n\nconst FILENAME = 'environments.json';\n\ninterface DiskEncryptedCache {\n envSlots: Record<string, string>;\n}\n\ntype ChangeListener = () => void;\n\nclass EnvironmentStore {\n private environments: Map<string, Environment> = new Map();\n private loaded = false;\n /** Cache of encrypted secret values as last written to disk */\n private diskEncryptedSlots: Map<string, DiskEncryptedCache> = new Map();\n /**\n * Les secrets qu'aucune clé chargée n'a ouverts, par environnement.\n *\n * Vides en mémoire, ils doivent repartir sur le disque sous leur forme\n * chiffrée : c'est ce que retient cette liste. Voir `keepUnreadableSecrets`.\n */\n private unreadableSecrets: Map<string, Set<string>> = new Map();\n /**\n * Coffres dont le fichier a bougé depuis la lecture.\n *\n * On ne les réécrit pas. Ni avec notre copie — elle décrirait l'état d'avant\n * la réparation — ni sans elle, ce qui effacerait les secrets qu'elle\n * protège. Entre les deux, la seule issue sûre est de ne pas toucher au\n * fichier et de laisser le prochain chargement faire foi.\n */\n private staleRoots: Set<string> = new Set();\n /**\n * L'état du disque au dernier chargement — voir `ProjectStore.fingerprint`.\n *\n * `staleRoots` dit « ne réécris pas ce fichier, il a bougé » ; celui-ci dit\n * « relis-le ». Les deux vont ensemble : refuser d'écrire protège le travail\n * de l'autre instance, mais tant que la mémoire n'est pas reprise, l'écriture\n * refusée l'est pour toujours et la modification de l'utilisateur se perd.\n */\n private fingerprint = '';\n private readonly disk = new StoreDiskCoordinator();\n private listeners: Set<ChangeListener> = new Set();\n\n /** Notified after every persisted mutation, for the cloud sync bridge. */\n onChange(fn: ChangeListener): () => void {\n this.listeners.add(fn);\n return () => this.listeners.delete(fn);\n }\n\n private notify(): void {\n for (const fn of this.listeners) fn();\n }\n\n /**\n * Which vault each environment was read from, so a save puts it back where it\n * belongs even before its project has been loaded.\n */\n private roots: Map<string, string> = new Map();\n /** L'organisation d'où vient un environnement reçu du cloud — voir `vaultOf`. */\n private remoteOrgs: Map<string, string> = new Map();\n\n /**\n * Oublier ce qui a été lu, pour tout relire sous la clé courante.\n *\n * Appelé après l'adoption d'une clé d'organisation : le disque vient d'être\n * re-chiffré sous les pieds du store, si bien que sa mémoire décrit un état\n * qui n'existe plus. La laisser en place n'affichait pas seulement des\n * comptes périmés — la sauvegarde suivante réécrivait l'ancien chiffré\n * par-dessus le nouveau, et défaisait l'adoption.\n */\n resetCache(): void {\n this.environments.clear();\n this.diskEncryptedSlots.clear();\n this.unreadableSecrets.clear();\n this.roots.clear();\n this.remoteOrgs.clear();\n this.loaded = false;\n // Les clients abonnés tiennent l'ancienne liste : sans ce signal, l'écran\n // ne se corrigerait qu'au prochain appel qu'il ferait de lui-même.\n this.notify();\n }\n\n /**\n * Combien de secrets ce coffre garde chiffrés sans savoir les ouvrir, par\n * organisation (`null` pour la machine).\n *\n * Ils sont déjà préservés à l'écriture (`keepUnreadableSecrets`) ; ce qui\n * manquait, c'est de le dire. Un secret qui s'affiche vide et se sauvegarde\n * intact est rassurant sur le disque et déroutant à l'écran.\n */\n async unreadableByVault(): Promise<Map<string | null, number>> {\n await this.load();\n const out = new Map<string | null, number>();\n for (const [environmentId, failed] of this.unreadableSecrets) {\n if (!failed.size) continue;\n const environment = this.environments.get(environmentId);\n const vault = (environment ? this.vaultOf(environment) : undefined) ?? null;\n out.set(vault, (out.get(vault) ?? 0) + failed.size);\n }\n return out;\n }\n\n private getFilePath(root: string): string {\n return join(root, FILENAME);\n }\n\n /**\n * The vault an environment must be written to: its project's.\n *\n * An environment names its project by id alone, and that id can answer for a\n * project in each organization. The vault it was read from names the couple —\n * so it is handed over as the tie-breaker rather than left as a mere fallback.\n *\n * Falls back to where it was last read, then to the local vault — an\n * environment whose project is unknown belongs to the launch directory, which\n * is where it lived before vaults existed.\n */\n /**\n * La clé sous laquelle chiffrer cet environnement.\n *\n * La provenance l'emporte sur le coffre tant que le projet n'est pas local :\n * un environnement reçu du cloud arrive avant lui, et `rootFor` désignerait\n * alors le répertoire de lancement — donc la clé de la machine plutôt que\n * celle de l'organisation qui a chiffré ces secrets.\n */\n private vaultOf(environment: Environment): string | undefined {\n return this.remoteOrgs.get(environment.id) ?? vaultIdOfRoot(this.rootFor(environment));\n }\n\n private rootFor(environment: Environment): string {\n const known = this.roots.get(environment.id) ?? null;\n const projectRoot = environment.projectId\n ? rootOfProjectAmong(environment.projectId, known)\n : null;\n return projectRoot ?? known ?? localVaultRoot();\n }\n\n /**\n * Le projet d'un environnement, organisation comprise.\n *\n * L'environnement ne nomme que l'id ; le coffre d'où il vient fournit\n * l'organisation, et c'est ce couple qu'il faut pour agir sur son projet.\n */\n projectRefOf(environment: Environment): ProjectRef | null {\n if (!environment.projectId) return null;\n return refOfProjectAmong(environment.projectId, this.roots.get(environment.id) ?? null);\n }\n\n /**\n * The vault holding the environment that defines a variable.\n *\n * Overrides answer a variable, not a project: this is what lets them find the\n * same vault without re-resolving an id that may be ambiguous.\n */\n async rootOfVariable(variableId: string): Promise<string | null> {\n await this.load();\n for (const environment of this.environments.values()) {\n if (environment.variables && variableId in environment.variables) {\n return this.rootFor(environment);\n }\n }\n return null;\n }\n\n private extractEncryptedCache(environment: Environment): DiskEncryptedCache {\n const envSlots = extractEncryptedVariableSlots(\n environment.variables as Record<string, { value: VariableSlot }>,\n );\n return { envSlots };\n }\n\n /**\n * `vault` est fourni quand l'appelant sait à qui appartient l'environnement\n * mieux que le disque : à l'arrivée d'une entité distante, son projet n'est\n * pas encore local, et le coffre déduit serait celui du répertoire de\n * lancement — donc la mauvaise clé.\n */\n private encryptEnvironment(environment: Environment, vault?: string): Environment {\n const cache = this.diskEncryptedSlots.get(environment.id);\n\n // Encrypt env variables\n let encryptedVars = environment.variables;\n if (environment.variables && Object.keys(environment.variables).length > 0) {\n encryptedVars = encryptVariableSlots(\n environment.variables as Record<string, { value: VariableSlot }>,\n cache?.envSlots,\n // La clé est celle du coffre où l'environnement sera écrit : les\n // secrets d'une organisation sont chiffrés par la sienne.\n vault ?? this.vaultOf(environment),\n ) as Environment['variables'];\n }\n\n return { ...environment, variables: this.keepUnreadableSecrets(environment.id, encryptedVars) };\n }\n\n /**\n * Réécrire un secret illisible tel qu'il est sur le disque, jamais à blanc.\n *\n * Un secret qui ne s'ouvre pas est vide en mémoire (voir\n * `decryptVariableSlots`) : le chiffrer donnerait un chiffré de la chaîne\n * vide, et la sauvegarde effacerait pour de bon une valeur dont il ne\n * manquait que la clé. Son chiffré d'origine est encore là — c'est celui que\n * `diskEncryptedSlots` a mis de côté avant le déchiffrement — et c'est lui\n * qui repart sur le disque.\n *\n * La condition tient à la valeur en mémoire : tant qu'elle est vide, la\n * variable n'a pas été retouchée et son chiffré fait foi. Dès que\n * l'utilisateur en saisit une nouvelle, elle l'emporte — et vider un secret\n * volontairement reste possible, puisque cela ne concerne que les variables\n * dont le déchiffrement a échoué.\n */\n private keepUnreadableSecrets(\n environmentId: string,\n variables: Environment['variables'],\n ): Environment['variables'] {\n const failed = this.unreadableSecrets.get(environmentId);\n if (!failed?.size || !variables) return variables;\n const onDisk = this.diskEncryptedSlots.get(environmentId)?.envSlots ?? {};\n const result = { ...variables };\n for (const variableId of failed) {\n const ciphertext = onDisk[variableId];\n const variable = result[variableId];\n if (!ciphertext || !variable || variable.value.value) continue;\n result[variableId] = { ...variable, value: { ...variable.value, value: ciphertext } };\n }\n return result;\n }\n\n private decryptEnvironment(\n environment: Environment,\n vault?: string,\n unreadable: Map<string, Set<string>> = this.unreadableSecrets,\n ): Environment {\n // Decrypt env variables\n let decryptedVars = environment.variables;\n if (environment.variables && Object.keys(environment.variables).length > 0) {\n const failed = new Set<string>();\n decryptedVars = decryptVariableSlots(\n environment.variables as Record<string, { value: VariableSlot }>,\n `environment ${environment.id}`,\n (variableId) => failed.add(variableId),\n vault ?? this.vaultOf(environment),\n ) as Environment['variables'];\n if (failed.size > 0) unreadable.set(environment.id, failed);\n else unreadable.delete(environment.id);\n }\n\n return { ...environment, variables: decryptedVars };\n }\n\n /** Ce que le disque porte : un fichier d'environnements par coffre. */\n private async diskFingerprint(): Promise<string> {\n return fingerprintFiles((await allVaultRoots()).map((root) => this.getFilePath(root)));\n }\n\n /**\n * Read every vault — the launch directory and each materialized cloud project.\n *\n * The roots come from the disk rather than from the project store, so loading\n * environments never has to wait on projects being loaded first (the project\n * store reads environments while absorbing a project, which would deadlock).\n */\n private async load(): Promise<void> {\n await this.disk.load(async () => {\n const fingerprint = await this.diskFingerprint();\n if (this.loaded && fingerprint === this.fingerprint) return null;\n // Les projets d'abord : tant qu'ils sont inconnus, chaque environnement\n // résoudrait vers le coffre de lancement et y serait réécrit à la première\n // sauvegarde — hors de son organisation.\n await ensureProjectsLoaded();\n // Locked: nothing can be decrypted, and marking the store loaded with\n // half the data would hide the rest until a restart.\n if (!getEncryptionKey()) return null;\n const next = await this.readVaults();\n return () => {\n this.environments = next.environments;\n this.diskEncryptedSlots = next.diskEncryptedSlots;\n this.roots = next.roots;\n this.unreadableSecrets = next.unreadableSecrets;\n this.fingerprint = fingerprint;\n this.loaded = true;\n };\n });\n }\n\n /** Lire tous les coffres dans des tables neuves, que `load` substitue d'un coup. */\n private async readVaults(): Promise<{\n environments: Map<string, Environment>;\n diskEncryptedSlots: Map<string, DiskEncryptedCache>;\n roots: Map<string, string>;\n unreadableSecrets: Map<string, Set<string>>;\n }> {\n const environments = new Map<string, Environment>();\n const diskEncryptedSlots = new Map<string, DiskEncryptedCache>();\n const roots = new Map<string, string>();\n const unreadableSecrets = new Map<string, Set<string>>();\n for (const root of await allVaultRoots()) {\n try {\n const raw = await readFile(this.getFilePath(root), 'utf-8');\n // L'empreinte du fichier lu : les chiffrés mis de côté ne valent que\n // tant qu'il n'a pas changé sous nos pieds.\n await rememberFile(this.getFilePath(root));\n const data: Environment[] = JSON.parse(raw);\n const clash = data.find((e) => isVaultClash(root, roots.get(e.id)));\n if (clash) {\n markVaultConflict(root, `environnement ${clash.id}`);\n continue;\n }\n for (const e of data) {\n // Cache encrypted slots before decrypting\n diskEncryptedSlots.set(e.id, this.extractEncryptedCache(e));\n // Le coffre d'abord, le déchiffrement ensuite, et par la provenance :\n // le même id de projet peut nommer un projet dans deux organisations,\n // et résoudre par lui désignait l'autre clé — tous les secrets du\n // coffre échouaient, alors qu'ils étaient intacts.\n roots.set(e.id, root);\n environments.set(e.id, this.decryptEnvironment(e, vaultIdOfRoot(root), unreadableSecrets));\n }\n } catch {\n // No environments in this vault yet.\n }\n }\n return { environments, diskEncryptedSlots, roots, unreadableSecrets };\n }\n\n /**\n * Write each vault that holds — or held — an environment.\n *\n * A vault emptied by this save loses its file: an environment that moved to\n * another vault must not survive in the old one, and a `[]` left behind would\n * keep (or recreate) a `.runeya` in a directory that holds nothing.\n */\n /**\n * Repérer les coffres réparés sous nos pieds, avant d'écrire.\n *\n * Le test est fait ici, une fois par sauvegarde, plutôt que par\n * environnement : c'est le fichier du coffre qui change, pas la variable.\n */\n private async markStaleRoots(): Promise<void> {\n this.staleRoots.clear();\n for (const root of new Set(this.roots.values())) {\n const path = this.getFilePath(root);\n if (wasRead(path) && await hasChangedSinceRead(path)) this.staleRoots.add(root);\n }\n }\n\n private save(): Promise<void> {\n return this.disk.save(() => this.writeVaults());\n }\n\n private async writeVaults(): Promise<void> {\n await this.markStaleRoots();\n const byRoot = new Map<string, Environment[]>();\n // Every vault seen so far starts empty, so one that lost its last\n // environment is rewritten rather than left behind — sauf un coffre en\n // conflit, dont le contenu n'est pas à nous.\n for (const root of this.roots.values()) {\n if (!isVaultConflicted(root)) byRoot.set(root, []);\n }\n byRoot.set(localVaultRoot(), byRoot.get(localVaultRoot()) ?? []);\n\n for (const environment of this.environments.values()) {\n const root = this.rootFor(environment);\n const prepared = this.encryptEnvironment(environment);\n // Update disk cache with newly written encrypted values\n this.diskEncryptedSlots.set(prepared.id, this.extractEncryptedCache(prepared));\n this.roots.set(environment.id, root);\n if (isVaultConflicted(root)) continue;\n const bucket = byRoot.get(root);\n if (bucket) bucket.push(prepared);\n else byRoot.set(root, [prepared]);\n }\n\n for (const [root, environments] of byRoot) {\n if (this.staleRoots.has(root)) {\n console.warn(\n `[environment-store] ${this.getFilePath(root)} a changé depuis sa lecture —`\n + ' écriture ignorée pour ne pas écraser une réparation faite en dehors du serveur.',\n );\n continue;\n }\n const filePath = this.getFilePath(root);\n if (environments.length === 0) {\n // Un coffre vidé perd son fichier plutôt que d'en garder une liste\n // vide. Écrire `[]` recréait un `.runeya` dans le dépôt de lancement\n // alors que tous les projets vivent désormais dans le cloud — un\n // fichier fantôme qui apparaissait dans le git status de l'utilisateur.\n await rm(filePath, { force: true }).catch(() => {});\n continue;\n }\n try {\n await atomicWriteSecure(filePath, JSON.stringify(environments, null, 2));\n } catch (err) {\n // Chaque sauvegarde réécrit tous les coffres : celui d'un projet qu'on\n // supprime au même moment perd son dossier en cours d'écriture.\n if ((err as NodeJS.ErrnoException).code !== 'ENOENT') throw err;\n console.warn(`[environment-store] ${filePath} a disparu pendant l'écriture (projet supprimé ?) — coffre ignoré.`);\n continue;\n }\n // Notre propre écriture devient la nouvelle référence : sans ça, la\n // sauvegarde suivante prendrait ce fichier pour une réparation externe.\n await rememberFile(filePath);\n }\n\n // Nos propres écritures deviennent la référence : sans ça, le chargement\n // suivant les prendrait pour celles d'une autre instance et relirait tout.\n this.fingerprint = await this.diskFingerprint();\n\n this.notify();\n }\n\n /**\n * Rewrite every vault, moving entities that now belong elsewhere.\n *\n * Called once the project store knows where projects live: entities read from\n * the launch directory whose project turns out to be a cloud one are written\n * into that project's vault, and disappear from the directory they came from.\n */\n async relocateAll(): Promise<void> {\n await this.load();\n await this.save();\n }\n\n /**\n * Which project a variable belongs to, by walking the environments that\n * define it.\n *\n * Overrides are keyed by variable id alone — nothing in an override says\n * which project it belongs to — so this is what lets them be stored with\n * their project rather than in one machine-wide pile.\n */\n /**\n * Drop a project's environments from memory, without touching the disk.\n *\n * Used when a project stops being followed: its vault is removed as a whole,\n * and environments left in memory would be written back on the next save —\n * into the local vault, since their project is no longer known.\n */\n async forgetByProject(projectId: string): Promise<void> {\n await this.load();\n for (const [id, environment] of this.environments) {\n if (environment.projectId !== projectId) continue;\n this.environments.delete(id);\n this.diskEncryptedSlots.delete(id);\n this.unreadableSecrets.delete(id);\n this.roots.delete(id);\n this.remoteOrgs.delete(id);\n }\n this.notify();\n }\n\n /**\n * Les environnements d'un projet.\n *\n * `orgId` restreint au projet de cette organisation : deux projets homonymes\n * ont chacun les siens, et filtrer sur le seul `projectId` mélangeait les deux\n * listes à l'écran. Omis, le filtre reste sur l'id — ce que fait un appelant\n * qui n'a pas d'organisation à donner.\n */\n async list(projectId: string, orgId?: string | null): Promise<Environment[]> {\n await this.load();\n return this.ofProject(projectId, orgId);\n }\n\n /** Le filtre commun : l'id, puis le coffre quand l'organisation est connue. */\n private ofProject(projectId: string, orgId?: string | null): Environment[] {\n const byId = Array.from(this.environments.values()).filter(e => e.projectId === projectId);\n if (orgId === undefined) return byId;\n const root = vaultFor({ id: projectId, orgId }).root;\n return byId.filter(e => this.rootFor(e) === root);\n }\n\n async get(id: string): Promise<Environment | null> {\n await this.load();\n return this.environments.get(id) ?? null;\n }\n\n /**\n * `orgId` ne fait pas partie de l'environnement : il dit dans quel coffre le\n * poser. Un environnement neuf n'a pas encore de provenance, et son\n * `projectId` seul peut répondre pour un projet de chaque organisation — sans\n * cette précision, la création échouerait sur l'ambiguïté au lieu de viser le\n * bon coffre.\n */\n async create(input: CreateEnvironment, orgId?: string | null): Promise<Environment> {\n await this.load();\n const parsed = CreateEnvironmentSchema.parse(input);\n const environment: Environment = {\n id: randomUUID(),\n projectId: parsed.projectId,\n name: parsed.name,\n description: parsed.description,\n parentIds: parsed.parentIds,\n variables: parsed.variables,\n scope: parsed.scope,\n reference: parsed.reference,\n activateOn: parsed.activateOn,\n immutable: parsed.immutable,\n default: parsed.default,\n color: parsed.color,\n bgColor: parsed.bgColor,\n agentId: parsed.agentId,\n };\n // Exclusivity: if this env is default, unset default on all others in the same project\n if (environment.default) {\n for (const [id, e] of this.environments) {\n if (e.projectId === environment.projectId && e.default) {\n this.environments.set(id, { ...e, default: false });\n }\n }\n }\n this.environments.set(environment.id, environment);\n if (environment.projectId && orgId !== undefined) {\n this.roots.set(environment.id, vaultFor({ id: environment.projectId, orgId }).root);\n }\n await this.save();\n return environment;\n }\n\n async update(input: UpdateEnvironment): Promise<Environment | null> {\n await this.load();\n const existing = this.environments.get(input.id);\n if (!existing) return null;\n const updated: Environment = {\n ...existing,\n // Immutable environments: allow changing variables, color, description — but not name\n ...(!existing.immutable && input.name !== undefined && { name: input.name }),\n ...(input.description !== undefined && { description: input.description }),\n ...(input.parentIds !== undefined && { parentIds: input.parentIds }),\n ...(input.variables !== undefined && { variables: input.variables }),\n ...(input.scope !== undefined && { scope: input.scope }),\n ...(input.reference !== undefined && { reference: input.reference }),\n ...(input.activateOn !== undefined && { activateOn: input.activateOn }),\n ...(input.color !== undefined && { color: input.color }),\n ...(input.bgColor !== undefined && { bgColor: input.bgColor }),\n ...(input.default !== undefined && { default: input.default }),\n ...(input.agentId !== undefined && { agentId: input.agentId ?? undefined }),\n };\n // Exclusivity: if setting default: true, unset default on all others in the same project\n if (updated.default) {\n for (const [id, e] of this.environments) {\n if (id !== input.id && e.projectId === updated.projectId && e.default) {\n this.environments.set(id, { ...e, default: false });\n }\n }\n }\n this.environments.set(input.id, updated);\n await this.save();\n return updated;\n }\n\n async upsertVariable(environmentId: string, variableId: string, variable: Environment['variables'][string]): Promise<Environment | null> {\n const existing = this.environments.get(environmentId);\n if (!existing) return null;\n const variables = { ...existing.variables, [variableId]: variable };\n return this.update({ id: environmentId, variables });\n }\n\n async removeVariable(environmentId: string, variableId: string): Promise<Environment | null> {\n const existing = this.environments.get(environmentId);\n if (!existing) return null;\n const variables = { ...existing.variables };\n delete variables[variableId];\n return this.update({ id: environmentId, variables });\n }\n\n async delete(id: string): Promise<boolean> {\n await this.load();\n const env = this.environments.get(id);\n if (!env) return false;\n if (env.immutable) return false; // Can't delete immutable environments\n this.environments.delete(id);\n recordLocalRemoval('environments', id);\n await this.save();\n return true;\n }\n\n async getByProjectId(projectId: string, orgId?: string | null): Promise<Environment[]> {\n await this.load();\n return this.ofProject(projectId, orgId);\n }\n\n async listAllGlobal(): Promise<Environment[]> {\n await this.load();\n return Array.from(this.environments.values()).filter(e => e.scope === 'global');\n }\n\n // --- Scope-based Query Methods ---\n\n async listByScope(\n projectId: string, scope: 'global' | 'service', orgId?: string | null,\n ): Promise<Environment[]> {\n await this.load();\n return this.ofProject(projectId, orgId).filter(e => e.scope === scope);\n }\n\n /** Les environnements de service qui s'activent avec un environnement global. */\n async listByActivateOn(globalEnvId: string): Promise<Environment[]> {\n await this.load();\n return Array.from(this.environments.values())\n .filter(e => e.scope === 'service' && e.activateOn === globalEnvId);\n }\n\n async findServiceEnvironment(serviceId: string, globalEnvId: string): Promise<Environment | null> {\n await this.load();\n for (const e of this.environments.values()) {\n if (e.scope === 'service' && e.reference === serviceId && e.activateOn === globalEnvId) return e;\n }\n return null;\n }\n\n async findServiceEnvironments(serviceId: string): Promise<Environment[]> {\n await this.load();\n return Array.from(this.environments.values()).filter(e => e.scope === 'service' && e.reference === serviceId);\n }\n\n async deleteByReference(serviceId: string): Promise<void> {\n await this.load();\n let changed = false;\n for (const [id, e] of this.environments) {\n if (e.scope === 'service' && e.reference === serviceId) {\n this.environments.delete(id);\n recordLocalRemoval('environments', id);\n changed = true;\n }\n }\n if (changed) await this.save();\n }\n\n async deleteByActivateOn(globalEnvId: string): Promise<void> {\n await this.load();\n let changed = false;\n for (const [id, e] of this.environments) {\n if (e.scope === 'service' && e.activateOn === globalEnvId) {\n this.environments.delete(id);\n recordLocalRemoval('environments', id);\n changed = true;\n }\n }\n if (changed) await this.save();\n }\n\n /**\n * When a service is renamed, update the name of all its service-scoped environments\n * to keep the `${serviceName} (${globalEnvName})` pattern in sync.\n */\n async renameByReference(serviceId: string, newServiceName: string): Promise<void> {\n await this.load();\n let changed = false;\n for (const [id, e] of this.environments) {\n if (e.scope === 'service' && e.reference === serviceId && e.activateOn) {\n const globalEnv = this.environments.get(e.activateOn);\n if (!globalEnv) continue;\n this.environments.set(id, { ...e, name: `${newServiceName} (${globalEnv.name})` });\n changed = true;\n }\n }\n if (changed) await this.save();\n }\n\n /**\n * When a global environment is renamed, update the name of all service-scoped\n * environments that activateOn it to keep the naming pattern in sync.\n * Caller provides a serviceId→name map since environmentStore can't access serviceStore.\n */\n async renameByActivateOn(globalEnvId: string, newGlobalName: string, serviceNames: Map<string, string>): Promise<void> {\n await this.load();\n let changed = false;\n for (const [id, e] of this.environments) {\n if (e.scope === 'service' && e.activateOn === globalEnvId && e.reference) {\n const serviceName = serviceNames.get(e.reference);\n if (!serviceName) continue;\n this.environments.set(id, { ...e, name: `${serviceName} (${newGlobalName})` });\n changed = true;\n }\n }\n if (changed) await this.save();\n }\n\n // ---- Cloud sync ------------------------------------------------------\n\n /** Environments of the given projects, in their on-disk (encrypted) form. */\n async listEncryptedByProjectIds(projectIds: string[]): Promise<Environment[]> {\n await this.load();\n const wanted = new Set(projectIds);\n return Array.from(this.environments.values())\n .filter((e) => wanted.has(e.projectId))\n .map((e) => this.encryptEnvironment(e));\n }\n\n /**\n * Apply an environment received from the cloud, in its on-disk form.\n *\n * Validated rather than trusted, and diff-guarded against the on-disk form so\n * re-applying an identical environment neither saves nor notifies (loop-safe).\n */\n async applyRemoteUpsert(id: string, fields: unknown, vault?: string): Promise<{ created: boolean }> {\n await this.load();\n // Voir `vaultOf` : la sauvegarde qui suit doit chiffrer sous la clé qui\n // vient d'ouvrir, pas sous celle du coffre de repli.\n if (vault) this.remoteOrgs.set(id, vault);\n const parsed = EnvironmentSchema.safeParse({ ...(fields as object), id });\n if (!parsed.success) {\n console.error('[environment-store] Rejected remote environment %s:', id, parsed.error.message);\n return { created: false };\n }\n const incoming = parsed.data;\n const existing = this.environments.get(id);\n if (existing && JSON.stringify(this.encryptEnvironment(existing, vault)) === JSON.stringify(incoming)) {\n return { created: false };\n }\n this.diskEncryptedSlots.set(id, this.extractEncryptedCache(incoming));\n // The doc carries ciphertext for secret slots; in memory they are expected\n // in the clear, as `load()` keeps them.\n this.environments.set(id, this.decryptEnvironment(incoming, vault));\n await this.save();\n return { created: !existing };\n }\n\n /** Delete an environment that was removed on another peer. */\n async applyRemoteDelete(id: string): Promise<boolean> {\n await this.load();\n if (!this.environments.has(id)) return false;\n this.environments.delete(id);\n this.diskEncryptedSlots.delete(id);\n this.unreadableSecrets.delete(id);\n this.remoteOrgs.delete(id);\n await this.save();\n return true;\n }\n}\n\nexport const environmentStore = new EnvironmentStore();\n","import { createHash } from 'node:crypto';\n\nconst KEY_SIZE_BYTES = 32;\n\n/**\n * Keys in memory, one per vault.\n *\n * A machine can hold several vaults at once — the local `.runeya` and one per\n * organization it follows — and they do not share a key. The keyring is\n * therefore indexed by vault root, with `DEFAULT_VAULT` standing for \"the vault\n * this process was launched in\".\n *\n * Every accessor keeps its no-argument form, which addresses that default\n * vault: the whole server currently runs in a single vault, and only the code\n * that knowingly juggles several has to name one.\n */\nconst DEFAULT_VAULT = '\\u0000default';\nconst keyring = new Map<string, Buffer>();\n/**\n * Coffres dont la clé existe mais n'a pas pu être ouverte.\n *\n * Un coffre inconnu du trousseau retombe sur la clé machine — c'est ce qui\n * permet à une organisation matérialisée après le déverrouillage de\n * fonctionner, et c'est sans danger : elle n'a pas encore de clé à elle, donc\n * ses données sont déjà sous celle-ci. Un coffre *verrouillé*, lui, a une clé\n * propre qu'on n'a pas su ouvrir : y écrire sous la clé machine passerait par\n * dessus des données qu'on ne sait pas lire. Le repli s'arrête là.\n */\nconst lockedVaults = new Set<string>();\nlet _ciMode = false;\n\n// Pending legacy key holder — kept in memory between migration and setup\nlet _pendingLegacyKey: Buffer | null = null;\n\n/** True only when the key was loaded from RUNEYA_ENCRYPTION_KEY (CI/CD — no JWT required). */\nexport function isCiMode(): boolean {\n return _ciMode;\n}\n\n/** Load encryption key from env var (CI mode) */\nexport async function loadFromEnv(): Promise<boolean> {\n const keyHex = process.env['RUNEYA_ENCRYPTION_KEY'];\n if (!keyHex) return false;\n if (!/^[0-9a-f]{64}$/i.test(keyHex)) {\n throw new Error('RUNEYA_ENCRYPTION_KEY invalide : attendu 64 caractères hex');\n }\n console.log('');\n console.log('⚠ ATTENTION : RUNEYA_ENCRYPTION_KEY est défini — l\\'authentification par master password est désactivée.');\n console.log(' Cette variable d\\'environnement est réservée aux environnements CI/CD.');\n console.log(' Ne la définissez jamais sur une machine de développement.');\n console.log('');\n setEncryptionKeyInMemory(Buffer.from(keyHex, 'hex'));\n _ciMode = true;\n return true;\n}\n\n// ── Pending legacy key holder ──────────────────────────────────────────────\n// After legacy migration, the libsodium key is stored here (NOT in the main\n// singleton) so that hasEncryptionKey() returns false → server state = setup.\n// The key is consumed by /api/setup to write .encryption.key.enc.\n\nexport function setPendingLegacyKey(key: Buffer): void {\n if (key.length !== KEY_SIZE_BYTES) throw new Error('Taille de clé invalide');\n _pendingLegacyKey = key;\n}\n\nexport function getPendingLegacyKey(): Buffer | null {\n return _pendingLegacyKey;\n}\n\nexport function clearPendingLegacyKey(): void {\n _pendingLegacyKey = null;\n}\n\nexport function hasPendingLegacyKey(): boolean {\n return _pendingLegacyKey !== null;\n}\n\n/** Set the encryption key in memory (called after successful unlock/setup) */\nexport function setEncryptionKeyInMemory(key: Buffer, vault: string = DEFAULT_VAULT): void {\n if (key.length !== KEY_SIZE_BYTES) throw new Error('Taille de clé invalide');\n keyring.set(vault, key);\n lockedVaults.delete(vault);\n announceUnlock();\n}\n\n/**\n * Prévenus quand un coffre devient lisible.\n *\n * Tant qu'aucune clé n'est là, les magasins rendent des listes vides — sans\n * erreur, par conception. Ce qui a lu avant le déverrouillage tient donc une\n * vue vide qu'aucune écriture ne viendra corriger : l'interface se rattrape en\n * refaisant ses requêtes, mais l'icône de barre système, elle, ne redemande\n * rien de son propre chef. D'où ce signal, posé au seul endroit par lequel une\n * clé entre en mémoire.\n */\nconst unlockListeners = new Set<() => void>();\n\nexport function onVaultUnlocked(listener: () => void): () => void {\n unlockListeners.add(listener);\n return () => unlockListeners.delete(listener);\n}\n\nfunction announceUnlock(): void {\n for (const listener of unlockListeners) {\n try {\n listener();\n } catch {\n // Un abonné qui échoue ne doit pas empêcher le déverrouillage.\n }\n }\n}\n\n/** Clear the cached key (lock). Without a vault, clears the whole keyring. */\nexport function clearEncryptionKey(vault?: string): void {\n if (vault === undefined) {\n keyring.clear();\n lockedVaults.clear();\n } else {\n keyring.delete(vault);\n }\n}\n\n/**\n * Ce coffre a-t-il une clé À LUI ?\n *\n * Volontairement plus strict que `getEncryptionKey`, qui replie sur la clé\n * machine : la question « puis-je chiffrer ici ? » et la question « ce coffre\n * a-t-il sa propre clé ? » sont deux questions différentes, et les confondre\n * ferait passer une organisation qui n'a pas encore la sienne pour une\n * organisation déjà dotée.\n */\nexport function hasEncryptionKey(vault: string = DEFAULT_VAULT): boolean {\n return keyring.has(vault);\n}\n\nexport function getEncryptionKey(vault: string = DEFAULT_VAULT): Buffer | null {\n const own = keyring.get(vault);\n if (own) return own;\n if (vault === DEFAULT_VAULT || lockedVaults.has(vault)) return null;\n return keyring.get(DEFAULT_VAULT) ?? null;\n}\n\n/** Ce coffre a une clé propre que ce master password n'ouvre pas. */\nexport function markVaultLocked(vault: string): void {\n lockedVaults.add(vault);\n keyring.delete(vault);\n}\n\n/** Ce coffre a une clé propre qu'on n'a pas su ouvrir — rien n'en est lisible. */\nexport function isVaultLocked(vault: string): boolean {\n return lockedVaults.has(vault);\n}\n\n/** Ce coffre s'ouvre à nouveau (clé chargée, ou adoptée). */\nexport function clearVaultLock(vault: string): void {\n lockedVaults.delete(vault);\n}\n\nexport function deriveStableSecret(purpose: string, vault: string = DEFAULT_VAULT): string | null {\n const key = getEncryptionKey(vault);\n if (!key) return null;\n return createHash('sha256').update(key).update(purpose).digest('hex');\n}\n\n/** Vault roots holding a loaded key — for callers that unlock several at once. */\nexport function unlockedVaults(): string[] {\n return Array.from(keyring.keys()).filter((v) => v !== DEFAULT_VAULT);\n}\n\n// Legacy compat: ensureEncryptionKey for code that still calls it\n// Returns null if key not loaded yet (LOCKED/SETUP state)\nexport async function ensureEncryptionKey(): Promise<Buffer | null> {\n return getEncryptionKey();\n}\n\n// Legacy compat: setEncryptionKey (used by old setup router)\nexport async function setEncryptionKey(keyHex: string): Promise<void> {\n if (!/^[0-9a-f]{64}$/i.test(keyHex)) throw new Error('Invalid key format');\n setEncryptionKeyInMemory(Buffer.from(keyHex, 'hex'));\n}\n","/**\n * Les coffres dont le contenu ne peut pas être tenu en mémoire sans écraser\n * celui d'un autre.\n *\n * Deux organisations peuvent porter le même projet — même id de projet, et donc\n * les mêmes ids de services, d'environnements, de conversations, puisque le\n * second coffre est une copie du premier. Les stores de contenu, eux, indexent\n * par id d'entité : le dernier coffre lu écraserait le précédent, et la\n * sauvegarde suivante réécrirait le coffre perdant à partir de données qui ne\n * sont plus les siennes.\n *\n * Plutôt que d'élire un gagnant en silence, le coffre en second est déclaré en\n * conflit : son contenu est ignoré en mémoire, et surtout **plus jamais écrit**.\n * Les fichiers restent intacts sur le disque, prêts à servir dès que le conflit\n * est levé — en cessant de suivre l'un des deux projets.\n */\n\nimport { localVaultRoot } from './vault-resolver.js';\n\nconst conflicted = new Map<string, string>();\n\n/**\n * Le coffre `root` rapporte-t-il une entité déjà lue ailleurs (`heldIn`) au\n * point d'être une copie d'un autre projet ?\n *\n * Pas quand la première copie vient du coffre de lancement : il n'est la copie\n * d'aucun projet d'organisation. Une entité y naît tant qu'aucun projet ne la\n * revendique, puis passe dans le coffre du projet qui l'adopte — la copie de\n * départ qui traîne est un reste, et la sauvegarde suivante l'efface. En faire\n * un conflit écartait tout le coffre du projet, et ses autres entités avec.\n */\nexport function isVaultClash(root: string, heldIn: string | undefined): boolean {\n return heldIn !== undefined && heldIn !== root && heldIn !== localVaultRoot();\n}\n\nexport function markVaultConflict(root: string, detail: string): void {\n if (conflicted.has(root)) return;\n conflicted.set(root, detail);\n console.error(\n '[vaults] %s partage des identifiants avec un autre coffre (%s) — ' +\n 'son contenu est ignoré et laissé intact. Cessez de suivre l\\'un des deux projets.',\n root, detail,\n );\n}\n\nexport function isVaultConflicted(root: string): boolean {\n return conflicted.has(root);\n}\n\n/** Les coffres écartés, pour un diagnostic exposable à l'utilisateur. */\nexport function conflictedVaults(): { root: string; detail: string }[] {\n return Array.from(conflicted, ([root, detail]) => ({ root, detail }));\n}\n\n/** Test seam, et relecture après qu'un projet a cessé d'être suivi. */\nexport function resetVaultConflicts(): void {\n conflicted.clear();\n}\n","import { decryptValueWith, encryptValueWith } from '@runeya/packages-shared/node';\nimport { getEncryptionKey } from '../utils/encryption-key.js';\nimport type { VariableSlot } from '@runeya/packages-shared';\n\nexport { encryptValueWith, decryptValueWith };\n\n/**\n * `vault` désigne la clé à employer : l'identifiant d'une organisation, ou\n * l'absence pour la clé machine.\n *\n * Une donnée est chiffrée par la clé du coffre où elle est écrite, jamais par\n * « la » clé du processus : c'est ce qui permet à une organisation d'avoir la\n * sienne sans que le poste entier doive la partager. Les appelants qui ne\n * connaissent qu'un coffre gardent la forme sans argument.\n */\nexport function encryptValue(plaintext: string, vault?: string): string {\n return encryptValueWith(requireKey(vault), plaintext);\n}\n\nexport function decryptValue(encrypted: string, vault?: string): string {\n return decryptValueWith(requireKey(vault), encrypted);\n}\n\nfunction requireKey(vault?: string): Buffer {\n const key = getEncryptionKey(vault);\n if (!key) {\n throw new Error('Encryption key not loaded — please provide the key via setup UI');\n }\n return key;\n}\n\n/** Reuse existing ciphertext if plaintext is unchanged — keeps diffs stable */\nexport function stableEncryptValue(plaintext: string, existingEncrypted?: string, vault?: string): string {\n if (existingEncrypted) {\n try {\n if (decryptValue(existingEncrypted, vault) === plaintext) return existingEncrypted;\n } catch {\n // Existing value is corrupt — fall through to re-encrypt\n }\n }\n return encryptValue(plaintext, vault);\n}\n\ntype HasValueSlot = { value: VariableSlot; [k: string]: unknown };\n\n/** Encrypt secret Variable.value slots (environment variables — {value: VariableSlot}) */\nexport function encryptVariableSlots(\n variables: Record<string, HasValueSlot>,\n existingEncrypted?: Record<string, string>,\n vault?: string,\n): Record<string, HasValueSlot> {\n const result: Record<string, HasValueSlot> = {};\n for (const [key, variable] of Object.entries(variables)) {\n const slot = variable.value;\n if (slot.isSecret && slot.value) {\n result[key] = { ...variable, value: { ...slot, value: stableEncryptValue(slot.value, existingEncrypted?.[key], vault) } };\n } else {\n result[key] = { ...variable, value: { ...slot } };\n }\n }\n return result;\n}\n\n/**\n * Decrypt secret Variable.value slots (environment variables).\n *\n * A value that does not open becomes a blank *in memory* — nothing downstream\n * can be handed a ciphertext as if it were a secret. But a blank in memory is\n * one save away from a blank on disk, which destroys the only copy of a secret\n * whose key is merely absent (a vault read under another key, a key not loaded\n * yet). `onFailure` is how the caller learns which slots must keep their\n * on-disk form no matter what memory says.\n */\nexport function decryptVariableSlots(\n variables: Record<string, HasValueSlot>,\n contextLabel: string,\n onFailure?: (key: string) => void,\n vault?: string,\n): Record<string, HasValueSlot> {\n const result: Record<string, HasValueSlot> = {};\n for (const [key, variable] of Object.entries(variables)) {\n const slot = variable.value;\n if (slot.isSecret && slot.value) {\n try {\n result[key] = { ...variable, value: { ...slot, value: decryptValue(slot.value, vault) } };\n } catch (err) {\n console.error(`[crypto-helpers] Failed to decrypt variable \"${key}\" for ${contextLabel}: ${(err as Error).message} — la valeur chiffrée est conservée telle quelle sur le disque`);\n onFailure?.(key);\n result[key] = { ...variable, value: { ...slot, value: '' } };\n }\n } else {\n result[key] = { ...variable, value: { ...slot } };\n }\n }\n return result;\n}\n\n/** Extract encrypted slot values from Variable records (for stable-encrypt cache) */\nexport function extractEncryptedVariableSlots(\n variables: Record<string, HasValueSlot>,\n): Record<string, string> {\n const slots: Record<string, string> = {};\n for (const [key, variable] of Object.entries(variables)) {\n if (variable.value?.isSecret && variable.value?.value) {\n slots[key] = variable.value.value;\n }\n }\n return slots;\n}\n\n/**\n * Returns true if `s` looks like a value encrypted by `encryptValue()`.\n * Format: `<32hex>:<32hex>:<Nhex>` (iv:authTag:ciphertext).\n */\nexport function isEncryptedValue(s: string): boolean {\n const parts = s.split(':');\n return parts.length === 3 && /^[0-9a-f]{32}$/i.test(parts[0]) && /^[0-9a-f]{32}$/i.test(parts[1]);\n}\n"],"mappings":"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","names":["ref"]}