@memorax/memorax-code 0.1.1 → 0.1.3

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 (246) hide show
  1. package/README.md +16 -12
  2. package/bin/memorax-code-npm-preinstall.mjs +7 -2
  3. package/bin/memorax-code-opencode.mjs +4 -0
  4. package/bin/memorax-code-plugin-postinstall.mjs +424 -108
  5. package/docs/configuration.md +153 -29
  6. package/docs/troubleshooting.md +93 -7
  7. package/lib/dsh-plugin-install.mjs +22 -0
  8. package/lib/memorax-code-adapter-common/src/hooks/capture-cwd-hook.mjs +21 -14
  9. package/lib/memorax-code-adapter-common/src/hooks/ensure-backend-runner.mjs +26 -7
  10. package/lib/memorax-code-adapter-common/src/hooks/memory-skill-reminder-hook.mjs +86 -95
  11. package/lib/memorax-code-adapter-common/src/hooks/memory-skill-reminder-policy.mjs +58 -0
  12. package/lib/memorax-code-adapter-common/src/repo-memory/repo-memory-auto-build.mjs +38 -0
  13. package/lib/memorax-code-adapter-common/src/repo-memory/repo-memory-job-supervisor.mjs +1 -1
  14. package/lib/memorax-code-adapter-common/src/windows-cli-invocation.mjs +13 -1
  15. package/lib/memorax-code-backend/dist/app/backend-server.js +210 -0
  16. package/lib/memorax-code-backend/dist/{server-observability.js → app/memory-observability.js} +4 -4
  17. package/lib/memorax-code-backend/dist/{backend-state.js → app/state.js} +1 -1
  18. package/lib/memorax-code-backend/dist/{claude-adapter-lifecycle.js → clients/claude/lifecycle.js} +2 -2
  19. package/lib/memorax-code-backend/dist/{claude-memory-hook-runtime.js → clients/claude/memory-hook-runtime.js} +16 -9
  20. package/lib/memorax-code-backend/dist/clients/codex/lifecycle.js +131 -0
  21. package/lib/memorax-code-backend/dist/{codex-memory-hook-runtime.js → clients/codex/memory-hook-runtime.js} +18 -11
  22. package/lib/memorax-code-backend/dist/{codex-plugin-hooks.js → clients/codex/plugin-hooks.js} +1 -1
  23. package/lib/memorax-code-backend/dist/{codex-plugin-install.js → clients/codex/plugin-install.js} +6 -6
  24. package/lib/memorax-code-backend/dist/clients/dsh/lifecycle.js +75 -0
  25. package/lib/memorax-code-backend/dist/clients/dsh/memory-hook-runtime.js +258 -0
  26. package/lib/memorax-code-backend/dist/clients/dsh/session-turn.js +249 -0
  27. package/lib/memorax-code-backend/dist/clients/opencode/lifecycle.js +54 -0
  28. package/lib/memorax-code-backend/dist/clients/opencode/memory-hook-runtime.js +277 -0
  29. package/lib/memorax-code-backend/dist/clients/opencode/message-turn.js +78 -0
  30. package/lib/memorax-code-backend/dist/codex-adapter-lifecycle.js +1 -131
  31. package/lib/memorax-code-backend/dist/{memorax-code-config.js → config/memorax-code.js} +32 -4
  32. package/lib/memorax-code-backend/dist/{server-cli.js → entrypoints/backend-cli.js} +157 -34
  33. package/lib/memorax-code-backend/dist/jsonl-append.js +1 -75
  34. package/lib/memorax-code-backend/dist/{active-client-selection.js → lifecycle/active-clients.js} +12 -1
  35. package/lib/memorax-code-backend/dist/{backend-service-cleanup.js → lifecycle/backend/cleanup.js} +1 -1
  36. package/lib/memorax-code-backend/dist/{backend-service-record.js → lifecycle/backend/record.js} +1 -1
  37. package/lib/memorax-code-backend/dist/{backend-service-result.js → lifecycle/backend/result.js} +2 -2
  38. package/lib/memorax-code-backend/dist/{service.js → lifecycle/backend/service.js} +16 -16
  39. package/lib/memorax-code-backend/dist/{backend-token-record.js → lifecycle/backend/token-record.js} +1 -1
  40. package/lib/memorax-code-backend/dist/{backend-service-token.js → lifecycle/backend/token.js} +2 -2
  41. package/lib/memorax-code-backend/dist/lifecycle/client-plugin-removal.js +109 -0
  42. package/lib/memorax-code-backend/dist/{client-selection.js → lifecycle/client-selection.js} +11 -5
  43. package/lib/memorax-code-backend/dist/{backend-lifecycle-lock.js → lifecycle/lock.js} +1 -1
  44. package/lib/memorax-code-backend/dist/{memorax-code-lifecycle.js → lifecycle/orchestrator.js} +325 -39
  45. package/lib/memorax-code-backend/dist/memorax-cli.js +3 -1
  46. package/lib/memorax-code-backend/dist/memorax-code.js +1 -1
  47. package/lib/memorax-code-backend/dist/{automatic-memory-retrieval.js → memory/automatic-retrieval.js} +3 -3
  48. package/lib/memorax-code-backend/dist/{automatic-memory-writeback.js → memory/automatic-writeback.js} +82 -21
  49. package/lib/memorax-code-backend/dist/{memory-cli.js → memory/cli.js} +45 -10
  50. package/lib/memorax-code-backend/dist/{memory-hook-command.js → memory/hook-command.js} +156 -9
  51. package/lib/memorax-code-backend/dist/memory/observability.js +1 -0
  52. package/lib/memorax-code-backend/dist/memory/payload-redaction.js +212 -0
  53. package/lib/memorax-code-backend/dist/{memory-reminder-trace-recorder.js → memory/reminder-trace-recorder.js} +20 -7
  54. package/lib/memorax-code-backend/dist/{repository-memory-context.js → memory/repository-session.js} +25 -4
  55. package/lib/memorax-code-backend/dist/{memory-service.js → memory/service.js} +30 -6
  56. package/lib/memorax-code-backend/dist/{memory-turn-coordinator.js → memory/turn-coordinator.js} +7 -3
  57. package/lib/memorax-code-backend/dist/{memory-writeback-buffer.js → memory/writeback-buffer.js} +31 -2
  58. package/lib/memorax-code-backend/dist/{memory-writeback-chunk.js → memory/writeback-chunk.js} +1 -1
  59. package/lib/memorax-code-backend/dist/{memory-writeback-reconciler.js → memory/writeback-reconciler.js} +6 -6
  60. package/lib/memorax-code-backend/dist/{memory-writeback-task-projection.js → memory/writeback-task-projection.js} +4 -4
  61. package/lib/memorax-code-backend/dist/{memorax-adapter.js → provider/memorax/adapter.js} +5 -5
  62. package/lib/memorax-code-backend/dist/{memorax-config.js → provider/memorax/config.js} +4 -4
  63. package/lib/memorax-code-backend/dist/{memorax-http.js → provider/memorax/http.js} +1 -1
  64. package/lib/memorax-code-backend/dist/{repo-memory-readiness.js → repository/readiness.js} +3 -3
  65. package/lib/memorax-code-backend/dist/{repository-memory-scope.js → repository/scope.js} +81 -33
  66. package/lib/memorax-code-backend/dist/server.js +3 -212
  67. package/lib/memorax-code-backend/dist/service-entrypoint.js +1 -1
  68. package/lib/memorax-code-backend/dist/{debug-log.js → shared/debug-log.js} +1 -1
  69. package/lib/memorax-code-backend/dist/shared/jsonl-append.js +75 -0
  70. package/lib/memorax-code-backend/dist/shared/windows-cli-invocation.js +148 -0
  71. package/lib/memorax-code-backend/dist/{trace-config.js → trace/config.js} +43 -5
  72. package/lib/memorax-code-backend/dist/{trace-context.js → trace/context.js} +53 -2
  73. package/lib/memorax-code-backend/dist/{trace-store.js → trace/store.js} +3 -3
  74. package/lib/memorax-code-backend/dist/{server-health.js → transport/http/health.js} +1 -1
  75. package/lib/memorax-code-backend/dist/{server-memory-hook.js → transport/http/memory-hook.js} +3 -3
  76. package/lib/memorax-code-backend/dist/{server-http.js → transport/http/request.js} +1 -1
  77. package/lib/memorax-code-backend/dist/{claude-local-transcript.js → viewer/history/claude-transcript.js} +3 -3
  78. package/lib/memorax-code-backend/dist/{memory-viewer-session-title.js → viewer/history/session-title.js} +1 -1
  79. package/lib/memorax-code-backend/dist/{server-memory-viewer.js → viewer/http/public-routes.js} +25 -14
  80. package/lib/memorax-code-backend/dist/viewer/model.js +1 -0
  81. package/lib/memorax-code-backend/dist/{memory-viewer-activity.js → viewer/projection/activity.js} +2 -2
  82. package/lib/memorax-code-backend/dist/{memory-viewer-history-projection.js → viewer/projection/history.js} +1 -1
  83. package/lib/memorax-code-backend/dist/{memory-viewer-observability.js → viewer/projection/observability.js} +1 -1
  84. package/lib/memorax-code-backend/dist/{memory-viewer-user-projection.js → viewer/projection/user.js} +1 -1
  85. package/lib/memorax-code-backend/dist/{memory-viewer-writeback-status.js → viewer/projection/writeback-status.js} +1 -1
  86. package/lib/memorax-code-backend/dist/{memory-viewer-store.js → viewer/store.js} +59 -32
  87. package/lib/memorax-code-backend/dist/viewer/ui/icon.js +1 -0
  88. package/lib/memorax-code-backend/dist/{memory-viewer-user-html.js → viewer/ui/user-html.js} +14 -12
  89. package/lib/memorax-code-backend/dist/windows-cli-invocation.js +1 -148
  90. package/lib/memorax-code-backend/package.json +3 -3
  91. package/lib/memorax-code-claude-adapter/.claude-plugin/plugin.json +1 -1
  92. package/lib/memorax-code-claude-adapter/hooks/runtime-shell.json +1 -1
  93. package/lib/memorax-code-claude-adapter/package.json +1 -1
  94. package/lib/memorax-code-claude-adapter/runtime-hooks/memory-turn.mjs +5 -0
  95. package/lib/memorax-code-claude-adapter/skills/memorax-code/SKILL.md +23 -15
  96. package/lib/memorax-code-claude-adapter/skills/memorax-code/defaults.json +8 -5
  97. package/lib/memorax-code-claude-adapter/skills/memorax-code/references/memorax-add.md +5 -1
  98. package/lib/memorax-code-claude-adapter/skills/memorax-code/references/memorax-search.md +40 -10
  99. package/lib/memorax-code-claude-adapter/skills/memorax-code/references/personal-read.md +1 -1
  100. package/lib/memorax-code-claude-adapter/skills/memorax-code/references/personal-write.md +33 -13
  101. package/lib/memorax-code-claude-adapter/skills/memorax-code/references/repo-build.md +62 -13
  102. package/lib/memorax-code-claude-adapter/skills/memorax-code/references/repo-read.md +11 -4
  103. package/lib/memorax-code-claude-adapter/skills/memorax-code/references/repo-templates.md +179 -59
  104. package/lib/memorax-code-claude-adapter/skills/memorax-code/references/repo-update.md +18 -7
  105. package/lib/memorax-code-claude-adapter/skills/memorax-code/scripts/collect_all.py +122 -39
  106. package/lib/memorax-code-claude-adapter/skills/memorax-code/scripts/detect_updates.py +73 -10
  107. package/lib/memorax-code-claude-adapter/skills/memorax-code/scripts/github_resource_facets.py +9 -1
  108. package/lib/memorax-code-claude-adapter/skills/memorax-code/scripts/gitlab_resource_facets.py +9 -1
  109. package/lib/memorax-code-claude-adapter/skills/memorax-code/scripts/validate_memory.py +23 -1
  110. package/lib/memorax-code-claude-adapter/src/plugin-install.mjs +2 -0
  111. package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/.claude-plugin/plugin.json +1 -1
  112. package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/hooks/runtime-shell.json +1 -1
  113. package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/memorax-code-adapter-common/src/hooks/capture-cwd-hook.mjs +21 -14
  114. package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/memorax-code-adapter-common/src/hooks/ensure-backend-runner.mjs +26 -7
  115. package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/memorax-code-adapter-common/src/hooks/memory-skill-reminder-hook.mjs +86 -95
  116. package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/memorax-code-adapter-common/src/hooks/memory-skill-reminder-policy.mjs +58 -0
  117. package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/memorax-code-adapter-common/src/repo-memory/repo-memory-auto-build.mjs +38 -0
  118. package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/memorax-code-adapter-common/src/repo-memory/repo-memory-job-supervisor.mjs +1 -1
  119. package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/memorax-code-adapter-common/src/windows-cli-invocation.mjs +13 -1
  120. package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/package.json +1 -1
  121. package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/runtime-hooks/memory-turn.mjs +5 -0
  122. package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/skills/memorax-code/SKILL.md +23 -15
  123. package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/skills/memorax-code/defaults.json +8 -5
  124. package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/skills/memorax-code/references/memorax-add.md +5 -1
  125. package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/skills/memorax-code/references/memorax-search.md +40 -10
  126. package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/skills/memorax-code/references/personal-read.md +1 -1
  127. package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/skills/memorax-code/references/personal-write.md +33 -13
  128. package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/skills/memorax-code/references/repo-build.md +62 -13
  129. package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/skills/memorax-code/references/repo-read.md +11 -4
  130. package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/skills/memorax-code/references/repo-templates.md +179 -59
  131. package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/skills/memorax-code/references/repo-update.md +18 -7
  132. package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/skills/memorax-code/scripts/collect_all.py +122 -39
  133. package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/skills/memorax-code/scripts/detect_updates.py +73 -10
  134. package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/skills/memorax-code/scripts/github_resource_facets.py +9 -1
  135. package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/skills/memorax-code/scripts/gitlab_resource_facets.py +9 -1
  136. package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/skills/memorax-code/scripts/validate_memory.py +23 -1
  137. package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/src/plugin-install.mjs +2 -0
  138. package/lib/memorax-code-codex-adapter/.codex-plugin/plugin.json +1 -1
  139. package/lib/memorax-code-codex-adapter/hooks/runtime-shell.json +1 -1
  140. package/lib/memorax-code-codex-adapter/package.json +1 -1
  141. package/lib/memorax-code-codex-adapter/runtime-hooks/memory-skill-reminder.mjs +16 -2
  142. package/lib/memorax-code-codex-adapter/skills/memorax-code/SKILL.md +23 -15
  143. package/lib/memorax-code-codex-adapter/skills/memorax-code/defaults.json +8 -5
  144. package/lib/memorax-code-codex-adapter/skills/memorax-code/references/memorax-add.md +5 -1
  145. package/lib/memorax-code-codex-adapter/skills/memorax-code/references/memorax-search.md +40 -10
  146. package/lib/memorax-code-codex-adapter/skills/memorax-code/references/personal-read.md +1 -1
  147. package/lib/memorax-code-codex-adapter/skills/memorax-code/references/personal-write.md +33 -13
  148. package/lib/memorax-code-codex-adapter/skills/memorax-code/references/repo-build.md +62 -13
  149. package/lib/memorax-code-codex-adapter/skills/memorax-code/references/repo-read.md +11 -4
  150. package/lib/memorax-code-codex-adapter/skills/memorax-code/references/repo-templates.md +179 -59
  151. package/lib/memorax-code-codex-adapter/skills/memorax-code/references/repo-update.md +18 -7
  152. package/lib/memorax-code-codex-adapter/skills/memorax-code/scripts/collect_all.py +122 -39
  153. package/lib/memorax-code-codex-adapter/skills/memorax-code/scripts/detect_updates.py +73 -10
  154. package/lib/memorax-code-codex-adapter/skills/memorax-code/scripts/github_resource_facets.py +9 -1
  155. package/lib/memorax-code-codex-adapter/skills/memorax-code/scripts/gitlab_resource_facets.py +9 -1
  156. package/lib/memorax-code-codex-adapter/skills/memorax-code/scripts/validate_memory.py +23 -1
  157. package/lib/memorax-code-dsh-adapter/cordis.patch.yml +10 -0
  158. package/lib/memorax-code-dsh-adapter/hooks/repo-memory-job.mjs +68 -0
  159. package/lib/memorax-code-dsh-adapter/package.json +69 -0
  160. package/lib/memorax-code-dsh-adapter/skills/memorax-code/SKILL.md +91 -0
  161. package/lib/memorax-code-dsh-adapter/skills/memorax-code/agents/claude.yaml +10 -0
  162. package/lib/memorax-code-dsh-adapter/skills/memorax-code/agents/openai.yaml +7 -0
  163. package/lib/memorax-code-dsh-adapter/skills/memorax-code/defaults.json +12 -0
  164. package/lib/memorax-code-dsh-adapter/skills/memorax-code/references/memorax-add.md +86 -0
  165. package/lib/memorax-code-dsh-adapter/skills/memorax-code/references/memorax-search.md +91 -0
  166. package/lib/memorax-code-dsh-adapter/skills/memorax-code/references/personal-read.md +46 -0
  167. package/lib/memorax-code-dsh-adapter/skills/memorax-code/references/personal-write.md +120 -0
  168. package/lib/memorax-code-dsh-adapter/skills/memorax-code/references/repo-build.md +319 -0
  169. package/lib/memorax-code-dsh-adapter/skills/memorax-code/references/repo-read.md +103 -0
  170. package/lib/memorax-code-dsh-adapter/skills/memorax-code/references/repo-templates.md +390 -0
  171. package/lib/memorax-code-dsh-adapter/skills/memorax-code/references/repo-update.md +127 -0
  172. package/lib/memorax-code-dsh-adapter/skills/memorax-code/scripts/collect_all.py +579 -0
  173. package/lib/memorax-code-dsh-adapter/skills/memorax-code/scripts/detect_updates.py +919 -0
  174. package/lib/memorax-code-dsh-adapter/skills/memorax-code/scripts/git_commit_facets.py +222 -0
  175. package/lib/memorax-code-dsh-adapter/skills/memorax-code/scripts/github_resource_facets.py +512 -0
  176. package/lib/memorax-code-dsh-adapter/skills/memorax-code/scripts/gitlab_resource_facets.py +517 -0
  177. package/lib/memorax-code-dsh-adapter/skills/memorax-code/scripts/prepare_repo_memory.py +411 -0
  178. package/lib/memorax-code-dsh-adapter/skills/memorax-code/scripts/user_profile_memory.py +528 -0
  179. package/lib/memorax-code-dsh-adapter/skills/memorax-code/scripts/validate_memory.py +248 -0
  180. package/lib/memorax-code-dsh-adapter/src/backend-client.mjs +119 -0
  181. package/lib/memorax-code-dsh-adapter/src/dsh-message.mjs +32 -0
  182. package/lib/memorax-code-dsh-adapter/src/dsh-version.mjs +18 -0
  183. package/lib/memorax-code-dsh-adapter/src/http-client.mjs +55 -0
  184. package/lib/memorax-code-dsh-adapter/src/index.mjs +72 -0
  185. package/lib/memorax-code-dsh-adapter/src/personal-context-worker.mjs +48 -0
  186. package/lib/memorax-code-dsh-adapter/src/personal-context.mjs +114 -0
  187. package/lib/memorax-code-dsh-adapter/src/plugin.mjs +724 -0
  188. package/lib/memorax-code-dsh-adapter/src/profile-lifecycle.mjs +1289 -0
  189. package/lib/memorax-code-dsh-adapter/src/protocol.mjs +145 -0
  190. package/lib/memorax-code-dsh-adapter/src/runtime-state.mjs +132 -0
  191. package/lib/memorax-code-opencode-adapter/hooks/repo-memory-job.mjs +37 -0
  192. package/lib/memorax-code-opencode-adapter/package.json +10 -0
  193. package/lib/memorax-code-opencode-adapter/skills/memorax-code/SKILL.md +91 -0
  194. package/lib/memorax-code-opencode-adapter/skills/memorax-code/agents/claude.yaml +10 -0
  195. package/lib/memorax-code-opencode-adapter/skills/memorax-code/agents/openai.yaml +7 -0
  196. package/lib/memorax-code-opencode-adapter/skills/memorax-code/defaults.json +12 -0
  197. package/lib/memorax-code-opencode-adapter/skills/memorax-code/references/memorax-add.md +86 -0
  198. package/lib/memorax-code-opencode-adapter/skills/memorax-code/references/memorax-search.md +91 -0
  199. package/lib/memorax-code-opencode-adapter/skills/memorax-code/references/personal-read.md +46 -0
  200. package/lib/memorax-code-opencode-adapter/skills/memorax-code/references/personal-write.md +120 -0
  201. package/lib/memorax-code-opencode-adapter/skills/memorax-code/references/repo-build.md +319 -0
  202. package/lib/memorax-code-opencode-adapter/skills/memorax-code/references/repo-read.md +103 -0
  203. package/lib/memorax-code-opencode-adapter/skills/memorax-code/references/repo-templates.md +390 -0
  204. package/lib/memorax-code-opencode-adapter/skills/memorax-code/references/repo-update.md +127 -0
  205. package/lib/memorax-code-opencode-adapter/skills/memorax-code/scripts/collect_all.py +579 -0
  206. package/lib/memorax-code-opencode-adapter/skills/memorax-code/scripts/detect_updates.py +919 -0
  207. package/lib/memorax-code-opencode-adapter/skills/memorax-code/scripts/git_commit_facets.py +222 -0
  208. package/lib/memorax-code-opencode-adapter/skills/memorax-code/scripts/github_resource_facets.py +512 -0
  209. package/lib/memorax-code-opencode-adapter/skills/memorax-code/scripts/gitlab_resource_facets.py +517 -0
  210. package/lib/memorax-code-opencode-adapter/skills/memorax-code/scripts/prepare_repo_memory.py +411 -0
  211. package/lib/memorax-code-opencode-adapter/skills/memorax-code/scripts/user_profile_memory.py +528 -0
  212. package/lib/memorax-code-opencode-adapter/skills/memorax-code/scripts/validate_memory.py +248 -0
  213. package/lib/memorax-code-opencode-adapter/src/adapter-paths.mjs +37 -0
  214. package/lib/memorax-code-opencode-adapter/src/cli.mjs +260 -0
  215. package/lib/memorax-code-opencode-adapter/src/diagnostics.mjs +31 -0
  216. package/lib/memorax-code-opencode-adapter/src/plugin-install.mjs +673 -0
  217. package/lib/memorax-code-opencode-adapter/src/plugin.mjs +536 -0
  218. package/lib/memorax-code-opencode-adapter/src/repo-memory-server-runner.mjs +207 -0
  219. package/lib/resolve-claude-command.mjs +154 -1
  220. package/lib/resolve-codex-command.mjs +56 -1
  221. package/lib/run-entrypoint.mjs +6 -0
  222. package/package.json +7 -3
  223. package/lib/memorax-code-backend/dist/client-plugin-removal.js +0 -67
  224. /package/lib/memorax-code-backend/dist/{claude-transcript-turn.js → clients/claude/transcript-turn.js} +0 -0
  225. /package/lib/memorax-code-backend/dist/{codex-effective-prompt.js → clients/codex/effective-prompt.js} +0 -0
  226. /package/lib/memorax-code-backend/dist/{codex-rollout-turn.js → clients/codex/rollout-turn.js} +0 -0
  227. /package/lib/memorax-code-backend/dist/{codex-session-turn-index.js → clients/codex/session-turn-index.js} +0 -0
  228. /package/lib/memorax-code-backend/dist/{codex-workspace-links.js → clients/codex/workspace-links.js} +0 -0
  229. /package/lib/memorax-code-backend/dist/{backend-env.js → config/backend-env.js} +0 -0
  230. /package/lib/memorax-code-backend/dist/{proxy-env.js → config/proxy-env.js} +0 -0
  231. /package/lib/memorax-code-backend/dist/{entrypoint.js → entrypoints/main.js} +0 -0
  232. /package/lib/memorax-code-backend/dist/{backend-process.js → lifecycle/backend/process.js} +0 -0
  233. /package/lib/memorax-code-backend/dist/{backend-shutdown-request.js → lifecycle/backend/shutdown-request.js} +0 -0
  234. /package/lib/memorax-code-backend/dist/{backend-status.js → lifecycle/backend/status.js} +0 -0
  235. /package/lib/memorax-code-backend/dist/{adapter-lifecycle-participant.js → lifecycle/contracts.js} +0 -0
  236. /package/lib/memorax-code-backend/dist/{install-watchdog.js → lifecycle/install-watchdog.js} +0 -0
  237. /package/lib/memorax-code-backend/dist/{memory-observability.js → lifecycle/participant.js} +0 -0
  238. /package/lib/memorax-code-backend/dist/{memory-project.js → memory/project.js} +0 -0
  239. /package/lib/memorax-code-backend/dist/{incremental-jsonl-projection.js → shared/incremental-jsonl-projection.js} +0 -0
  240. /package/lib/memorax-code-backend/dist/{utils.js → shared/record.js} +0 -0
  241. /package/lib/memorax-code-backend/dist/{server-json.js → transport/http/json.js} +0 -0
  242. /package/lib/memorax-code-backend/dist/{memory-viewer-data-projection-cache.js → viewer/projection/cache.js} +0 -0
  243. /package/lib/memorax-code-backend/dist/{memory-viewer-event-identity.js → viewer/projection/event-identity.js} +0 -0
  244. /package/lib/memorax-code-backend/dist/{memory-viewer-redaction.js → viewer/projection/redaction.js} +0 -0
  245. /package/lib/memorax-code-backend/dist/{memory-viewer-turn-reference.js → viewer/projection/turn-reference.js} +0 -0
  246. /package/lib/memorax-code-backend/dist/{memory-viewer-logo.js → viewer/ui/logo.js} +0 -0
@@ -0,0 +1,1289 @@
1
+ import { spawnSync } from "node:child_process";
2
+ import { createHash, randomUUID } from "node:crypto";
3
+ import {
4
+ copyFileSync,
5
+ existsSync,
6
+ lstatSync,
7
+ mkdirSync,
8
+ readFileSync,
9
+ readdirSync,
10
+ renameSync,
11
+ rmSync,
12
+ } from "node:fs";
13
+ import { createRequire } from "node:module";
14
+ import { homedir } from "node:os";
15
+ import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
16
+ import { isDeepStrictEqual } from "node:util";
17
+ import { fileURLToPath, pathToFileURL } from "node:url";
18
+
19
+ import {
20
+ DSH_TESTED_VERSIONS,
21
+ isTestedDshVersion,
22
+ parseDshVersion,
23
+ } from "./dsh-version.mjs";
24
+ import {
25
+ requireDshRuntimeAuthority,
26
+ requireEnabledDshRuntime,
27
+ } from "./runtime-state.mjs";
28
+
29
+ const MODULE_DIR = dirname(fileURLToPath(import.meta.url));
30
+ const ADAPTER_ROOT = resolve(MODULE_DIR, "..");
31
+ const stagedCommonRoot = resolve(ADAPTER_ROOT, "../memorax-code-adapter-common/src");
32
+ const sourceCommonRoot = resolve(MODULE_DIR, "../../memorax-code-adapter-common/src");
33
+ const commonRoot = existsSync(join(stagedCommonRoot, "config-utils.mjs"))
34
+ ? stagedCommonRoot
35
+ : sourceCommonRoot;
36
+ const stagedSkillRoot = resolve(ADAPTER_ROOT, "skills/memorax-code");
37
+ const sourceSkillRoot = resolve(MODULE_DIR, "../../memorax-code-codex-adapter/skills/memorax-code");
38
+ const skillRoot = existsSync(join(stagedSkillRoot, "SKILL.md"))
39
+ ? stagedSkillRoot
40
+ : sourceSkillRoot;
41
+ const {
42
+ atomicWriteJson,
43
+ readAdapterState,
44
+ withJsonFileLockAsync,
45
+ } = await import(pathToFileURL(join(commonRoot, "config-utils.mjs")).href);
46
+ const { resolveWindowsCliInvocation } = await import(
47
+ pathToFileURL(join(commonRoot, "windows-cli-invocation.mjs")).href
48
+ );
49
+
50
+ const STATE_VERSION = 1;
51
+ const RUNTIME = "dsh";
52
+ const ADAPTER_PACKAGE_NAME = "@memorax-code/dsh-memorax-code";
53
+ const LEGACY_ADAPTER_PACKAGE_NAMES = Object.freeze(["@memorax-code/dsh-adapter"]);
54
+ const MANAGED_ADAPTER_PACKAGE_NAMES = Object.freeze([
55
+ ADAPTER_PACKAGE_NAME,
56
+ ...LEGACY_ADAPTER_PACKAGE_NAMES,
57
+ ]);
58
+ const DSH_VERSION_TIMEOUT_MS = 10_000;
59
+ const DEFAULT_COMMAND_TIMEOUT_MS = 120_000;
60
+ const DEFAULT_LIFECYCLE_LOCK_TIMEOUT_MS = 600_000;
61
+ const PACKAGE_METADATA_FILE = ".memorax-code-package.json";
62
+ const PROFILE_BUNDLE_FILES = Object.freeze([
63
+ PACKAGE_METADATA_FILE,
64
+ "cordis.patch.yml",
65
+ "hooks/repo-memory-job.mjs",
66
+ "skills/memorax-code/SKILL.md",
67
+ "skills/memorax-code/agents/claude.yaml",
68
+ "skills/memorax-code/agents/openai.yaml",
69
+ "skills/memorax-code/defaults.json",
70
+ "skills/memorax-code/references/memorax-add.md",
71
+ "skills/memorax-code/references/memorax-search.md",
72
+ "skills/memorax-code/references/personal-read.md",
73
+ "skills/memorax-code/references/personal-write.md",
74
+ "skills/memorax-code/references/repo-build.md",
75
+ "skills/memorax-code/references/repo-read.md",
76
+ "skills/memorax-code/references/repo-templates.md",
77
+ "skills/memorax-code/references/repo-update.md",
78
+ "skills/memorax-code/scripts/collect_all.py",
79
+ "skills/memorax-code/scripts/detect_updates.py",
80
+ "skills/memorax-code/scripts/git_commit_facets.py",
81
+ "skills/memorax-code/scripts/github_resource_facets.py",
82
+ "skills/memorax-code/scripts/gitlab_resource_facets.py",
83
+ "skills/memorax-code/scripts/prepare_repo_memory.py",
84
+ "skills/memorax-code/scripts/user_profile_memory.py",
85
+ "skills/memorax-code/scripts/validate_memory.py",
86
+ "src/index.mjs",
87
+ "src/backend-client.mjs",
88
+ "src/dsh-message.mjs",
89
+ "src/dsh-version.mjs",
90
+ "src/http-client.mjs",
91
+ "src/personal-context-worker.mjs",
92
+ "src/personal-context.mjs",
93
+ "src/plugin.mjs",
94
+ "src/protocol.mjs",
95
+ "src/runtime-state.mjs",
96
+ "memorax-code-adapter-common/src/backend-connection.mjs",
97
+ "memorax-code-adapter-common/src/config-utils.mjs",
98
+ "memorax-code-adapter-common/src/hooks/ensure-backend-runner.mjs",
99
+ "memorax-code-adapter-common/src/hooks/memory-skill-reminder-policy.mjs",
100
+ "memorax-code-adapter-common/src/repo-memory/repo-memory-auto-build.mjs",
101
+ "memorax-code-adapter-common/src/repo-memory/repo-memory-job-context.mjs",
102
+ "memorax-code-adapter-common/src/repo-memory/repo-memory-job-marker.mjs",
103
+ "memorax-code-adapter-common/src/repo-memory/repo-memory-job-supervisor.mjs",
104
+ "memorax-code-adapter-common/src/repo-memory/repo-memory-job-worker.mjs",
105
+ "memorax-code-adapter-common/src/repo-memory/repo-procedure-memory-context.mjs",
106
+ "memorax-code-adapter-common/src/repo-memory/repo-memory-update-policy-evaluator.mjs",
107
+ "memorax-code-adapter-common/src/repo-memory/repo-memory-update-policy.mjs",
108
+ "memorax-code-adapter-common/src/repo-memory/repo-user-profile-context.mjs",
109
+ "memorax-code-adapter-common/src/runtime-record.mjs",
110
+ "memorax-code-adapter-common/src/windows-cli-invocation.mjs",
111
+ ]);
112
+
113
+ export function discoverDshProfiles(options = {}) {
114
+ const paths = resolvePaths(options);
115
+ let entries;
116
+ try {
117
+ entries = readdirSync(paths.profilesRoot, { withFileTypes: true });
118
+ } catch (error) {
119
+ if (error?.code === "ENOENT") return [];
120
+ throw error;
121
+ }
122
+ return entries
123
+ .filter((entry) => entry.isDirectory() && validProfileName(entry.name))
124
+ .map((entry) => readProfile(entry.name, join(paths.profilesRoot, entry.name)))
125
+ .filter(Boolean)
126
+ .sort((left, right) => left.name.localeCompare(right.name));
127
+ }
128
+
129
+ export function collectDshAdapterStatus(options = {}) {
130
+ try {
131
+ const paths = resolvePaths(options);
132
+ const state = readAdapterState(paths.statePath);
133
+ const stateProblem = validateState(state, paths);
134
+ const discoveredProfiles = discoverDshProfiles({ ...options, dshHome: paths.dshHome });
135
+ const managedNames = new Set(stateProblem ? [] : state?.profiles ?? []);
136
+ const profiles = projectProfileStatus(
137
+ discoveredProfiles,
138
+ managedNames,
139
+ true,
140
+ state?.runtimeBundleRoot,
141
+ stateProblem ? undefined : state,
142
+ );
143
+ const managed = Boolean(state) && !stateProblem;
144
+ const installed = profiles.length > 0
145
+ && profiles.every((profile) => profile.managed && profile.exists && profile.installed);
146
+ const base = {
147
+ integration: "plugin",
148
+ managed,
149
+ installed,
150
+ enabled: false,
151
+ profiles,
152
+ };
153
+ if (stateProblem) {
154
+ return { ok: false, ...base, reason: stateProblem.reason };
155
+ }
156
+ if (!state && profiles.length === 0) {
157
+ return { ok: true, ...base, skipped: true, reason: "no_existing_profiles" };
158
+ }
159
+
160
+ const dshCommand = resolveDshCommand(options, paths, state);
161
+ const compatibility = inspectDshCompatibility(options, paths, dshCommand);
162
+ const version = compatibility.dshVersion;
163
+ const versionStatus = {
164
+ dshVersionTested: compatibility.dshVersionTested,
165
+ testedDshVersions: [...DSH_TESTED_VERSIONS],
166
+ };
167
+ if (compatibility.reason === "dsh_version_unavailable") {
168
+ return {
169
+ ok: false,
170
+ ...base,
171
+ compatible: false,
172
+ reason: compatibility.reason,
173
+ };
174
+ }
175
+ if (compatibility.compatible !== true) {
176
+ return {
177
+ ok: true,
178
+ ...base,
179
+ ...(version ? { version } : {}),
180
+ compatible: false,
181
+ ...versionStatus,
182
+ skipped: true,
183
+ reason: compatibility.reason,
184
+ };
185
+ }
186
+ if (!state) {
187
+ return {
188
+ ok: true,
189
+ ...base,
190
+ version,
191
+ compatible: true,
192
+ ...versionStatus,
193
+ skipped: true,
194
+ reason: "not_managed",
195
+ };
196
+ }
197
+ if (state.enabled === true) {
198
+ try {
199
+ requireEnabledDshRuntime(state.runtimeBundleRoot);
200
+ } catch {
201
+ return {
202
+ ok: false,
203
+ ...base,
204
+ version,
205
+ compatible: true,
206
+ ...versionStatus,
207
+ reason: "runtime_authority_invalid",
208
+ };
209
+ }
210
+ }
211
+ return {
212
+ ok: true,
213
+ ...base,
214
+ enabled: state.enabled === true && installed,
215
+ version,
216
+ compatible: true,
217
+ ...versionStatus,
218
+ ...(state.enabled !== true
219
+ ? { reason: "disabled" }
220
+ : !installed
221
+ ? { reason: "profile_drift" }
222
+ : {}),
223
+ };
224
+ } catch {
225
+ return {
226
+ ok: false,
227
+ integration: "plugin",
228
+ managed: false,
229
+ installed: false,
230
+ enabled: false,
231
+ profiles: [],
232
+ reason: "dsh_status_unavailable",
233
+ };
234
+ }
235
+ }
236
+
237
+ /**
238
+ * Serialize one product lifecycle command with adapter recovery and DSH state
239
+ * mutation. The callback must use the supplied unlocked operations only.
240
+ */
241
+ export function withDshPluginLifecycleLock(options = {}, operation) {
242
+ if (typeof operation !== "function") {
243
+ throw new TypeError("DSH lifecycle lock requires an operation");
244
+ }
245
+ const paths = resolvePaths(options);
246
+ return withJsonFileLockAsync(paths.statePath, () => operation(Object.freeze({
247
+ status: () => readDshPluginStatusUnlocked(paths, options),
248
+ ensureInstalled: (overrides = {}) => ensureDshPluginInstalledUnlocked(
249
+ paths,
250
+ { ...options, ...overrides },
251
+ ),
252
+ activate: () => activateDshPluginInstallationUnlocked(paths, options),
253
+ quiesce: () => quiesceDshPluginInstallationUnlocked(paths),
254
+ disable: () => disableDshPluginInstallationUnlocked(paths, options, false),
255
+ remove: () => disableDshPluginInstallationUnlocked(paths, options, true),
256
+ })), {
257
+ timeoutMs: DEFAULT_LIFECYCLE_LOCK_TIMEOUT_MS,
258
+ });
259
+ }
260
+
261
+ function readDshPluginStatusUnlocked(paths, options) {
262
+ const state = readAdapterState(paths.statePath);
263
+ const stateProblem = validateState(state, paths);
264
+ if (stateProblem) return { ...stateProblem, action: "dsh-plugin-status" };
265
+ if (!state) {
266
+ return {
267
+ ok: true,
268
+ action: "dsh-plugin-status",
269
+ runtime: RUNTIME,
270
+ installed: false,
271
+ enabled: false,
272
+ managed: false,
273
+ profiles: [],
274
+ };
275
+ }
276
+
277
+ const profiles = discoverDshProfiles({ ...options, dshHome: paths.dshHome });
278
+ const managedProfiles = projectProfileStatus(
279
+ profiles,
280
+ new Set(state.profiles),
281
+ false,
282
+ state.runtimeBundleRoot,
283
+ state,
284
+ );
285
+ const installed = state.profiles.length > 0
286
+ && managedProfiles.every((profile) => profile.installed);
287
+ return {
288
+ ok: true,
289
+ action: "dsh-plugin-status",
290
+ runtime: RUNTIME,
291
+ installed,
292
+ enabled: state.enabled === true && installed,
293
+ managed: true,
294
+ authorityEnabled: state.enabled === true,
295
+ revision: state.updatedAt,
296
+ profiles: managedProfiles,
297
+ };
298
+ }
299
+
300
+ function ensureDshPluginInstalledUnlocked(paths, options) {
301
+ const state = readAdapterState(paths.statePath);
302
+ const stateProblem = validateState(state, paths);
303
+ if (stateProblem) return { ...stateProblem, action: "dsh-plugin-install" };
304
+ const claimedProfiles = (state?.profiles ?? []).map((name) => (
305
+ inspectProfile(name, join(paths.profilesRoot, name))
306
+ ));
307
+ const manifestProblem = managedProfileManifestProblem(claimedProfiles);
308
+ if (manifestProblem) return manifestProblem;
309
+
310
+ const profiles = discoverDshProfiles({ ...options, dshHome: paths.dshHome });
311
+ if (profiles.length === 0) {
312
+ if (state) atomicWriteJson(paths.statePath, disabledState(state, []));
313
+ return {
314
+ ok: !state,
315
+ action: "dsh-plugin-install",
316
+ runtime: RUNTIME,
317
+ installed: false,
318
+ enabled: false,
319
+ managed: Boolean(state),
320
+ ...(!state ? { skipped: true } : {}),
321
+ reason: "no_existing_profiles",
322
+ detectedProfiles: [],
323
+ };
324
+ }
325
+
326
+ const dshCommand = resolveDshCommand(options, paths, state);
327
+ const compatibility = inspectDshCompatibility(options, paths, dshCommand);
328
+ if (compatibility.compatible !== true) {
329
+ const nextState = state?.enabled === true
330
+ ? disabledState(state, state.profiles)
331
+ : state;
332
+ if (nextState && nextState !== state) atomicWriteJson(paths.statePath, nextState);
333
+ return {
334
+ ok: false,
335
+ action: "dsh-plugin-install",
336
+ runtime: RUNTIME,
337
+ installed: false,
338
+ enabled: false,
339
+ managed: Boolean(state),
340
+ detectedProfiles: profiles.map((profile) => profile.name),
341
+ ...compatibility,
342
+ };
343
+ }
344
+
345
+ const previouslyManaged = new Set(claimedProfiles
346
+ .filter((profile) => profile.status !== "directory_missing")
347
+ .map((profile) => profile.name));
348
+ const conflicts = profiles
349
+ .filter((profile) => profileMentionsAdapter(profile) && !previouslyManaged.has(profile.name))
350
+ .map((profile) => profile.name);
351
+ if (conflicts.length > 0) {
352
+ return {
353
+ ok: false,
354
+ action: "dsh-plugin-install",
355
+ runtime: RUNTIME,
356
+ reason: "profile_plugin_conflict",
357
+ profiles: conflicts,
358
+ };
359
+ }
360
+
361
+ const memoraxCodeCommand = resolveMemoraxCodeCommand(options.memoraxCodeCommand);
362
+ const metadata = {
363
+ version: 1,
364
+ memoraxCodeCommand,
365
+ memoraxCodeHome: paths.memoraxCodeHome,
366
+ dshHome: paths.dshHome,
367
+ dshCommand,
368
+ dshVersion: compatibility.dshVersion,
369
+ sourceAdapterRoot: paths.adapterRoot,
370
+ };
371
+ const runtimeBundleRoot = materializeRuntimeBundle(paths, metadata);
372
+
373
+ const now = new Date().toISOString();
374
+ const pendingState = {
375
+ version: STATE_VERSION,
376
+ runtime: RUNTIME,
377
+ integration: "plugin",
378
+ enabled: false,
379
+ dshHome: paths.dshHome,
380
+ memoraxCodeHome: paths.memoraxCodeHome,
381
+ adapterRoot: paths.adapterRoot,
382
+ runtimeBundleRoot,
383
+ memoraxCodeCommand,
384
+ dshCommand,
385
+ dshVersion: compatibility.dshVersion,
386
+ // Preserve prior claims and claim each target before invoking DSH so an
387
+ // interrupted or partial native add remains repairable and removable.
388
+ profiles: [...new Set([
389
+ ...previouslyManaged,
390
+ ...profiles.map((profile) => profile.name),
391
+ ])].sort(),
392
+ updatedAt: now,
393
+ };
394
+ atomicWriteJson(paths.statePath, pendingState);
395
+
396
+ const installedProfiles = [];
397
+ const failedProfiles = [];
398
+ const mutatedProfiles = [];
399
+ for (const profile of profiles) {
400
+ let current = inspectProfile(profile.name, profile.path);
401
+ if (current.status !== "valid") {
402
+ failedProfiles.push(current.status === "directory_missing"
403
+ ? { name: profile.name, reason: "profile_disappeared" }
404
+ : profileManifestFailure(profile.name));
405
+ continue;
406
+ }
407
+ if (!profileHasInstalledAdapter(current.profile, runtimeBundleRoot, pendingState)) {
408
+ const result = runDsh(options, paths, [
409
+ "plugin",
410
+ "--profile",
411
+ profile.name,
412
+ "add",
413
+ `file:${runtimeBundleRoot}`,
414
+ ], dshCommand);
415
+ current = inspectProfile(profile.name, profile.path);
416
+ if (previouslyManaged.has(profile.name)
417
+ || (current.status === "valid" && profileMentionsAdapter(current.profile))) {
418
+ mutatedProfiles.push(profile.name);
419
+ }
420
+ if (result.status !== 0
421
+ || result.error
422
+ || current.status !== "valid"
423
+ || !profileHasInstalledAdapter(current.profile, runtimeBundleRoot, pendingState)) {
424
+ failedProfiles.push(profileMutationFailure(
425
+ profile.name,
426
+ result,
427
+ current,
428
+ "dsh_bundle_not_activated",
429
+ ));
430
+ continue;
431
+ }
432
+ }
433
+
434
+ if (LEGACY_ADAPTER_PACKAGE_NAMES.some((packageName) => (
435
+ profileMentionsPackage(current.profile, packageName)
436
+ ))) {
437
+ mutatedProfiles.push(profile.name);
438
+ const cleanup = removeProfileAdapterPackages(
439
+ paths,
440
+ options,
441
+ profile.name,
442
+ LEGACY_ADAPTER_PACKAGE_NAMES,
443
+ dshCommand,
444
+ );
445
+ current = cleanup.profile;
446
+ if (cleanup.failure) {
447
+ failedProfiles.push(cleanup.failure);
448
+ continue;
449
+ }
450
+ }
451
+
452
+ if (current.status === "valid"
453
+ && profileHasInstalledAdapter(current.profile, runtimeBundleRoot, pendingState)) {
454
+ installedProfiles.push(profile.name);
455
+ } else {
456
+ failedProfiles.push(profileMutationFailure(
457
+ profile.name,
458
+ { status: 0 },
459
+ current,
460
+ "dsh_bundle_not_activated",
461
+ ));
462
+ }
463
+ }
464
+
465
+ const finalProfiles = pendingState.profiles.map((name) => (
466
+ inspectProfile(name, join(paths.profilesRoot, name))
467
+ ));
468
+ for (const profile of finalProfiles) {
469
+ if (failedProfiles.some((failure) => failure.name === profile.name)) continue;
470
+ if (profile.status === "manifest_unreadable") {
471
+ failedProfiles.push(profileManifestFailure(profile.name));
472
+ } else if (profile.status === "valid"
473
+ && !profileHasInstalledAdapter(profile.profile, runtimeBundleRoot, pendingState)) {
474
+ failedProfiles.push({ name: profile.name, reason: "dsh_bundle_not_activated" });
475
+ }
476
+ }
477
+ const managedProfiles = finalProfiles
478
+ .filter((profile) => profile.status !== "directory_missing")
479
+ .map((profile) => profile.name);
480
+ if (failedProfiles.length > 0 && state) {
481
+ const rollback = rollbackDshPluginReconciliation(
482
+ paths,
483
+ options,
484
+ state,
485
+ mutatedProfiles,
486
+ dshCommand,
487
+ );
488
+ const failureReason = pluginManagerFailureReason(failedProfiles);
489
+ return {
490
+ ok: false,
491
+ action: "dsh-plugin-install",
492
+ runtime: RUNTIME,
493
+ installed: false,
494
+ enabled: rollback.authorityRestored && state.enabled,
495
+ managed: true,
496
+ detectedProfiles: profiles.map((profile) => profile.name),
497
+ dshVersion: compatibility.dshVersion,
498
+ dshVersionTested: compatibility.dshVersionTested,
499
+ testedDshVersions: [...DSH_TESTED_VERSIONS],
500
+ installedProfiles,
501
+ failedProfiles,
502
+ ...(failureReason ? { reason: failureReason } : {}),
503
+ ...(rollback.failedProfiles.length > 0
504
+ ? { rollbackFailedProfiles: rollback.failedProfiles }
505
+ : {}),
506
+ };
507
+ }
508
+ const enabled = options.enabled !== false
509
+ && failedProfiles.length === 0
510
+ && managedProfiles.length > 0;
511
+ const nextState = {
512
+ ...pendingState,
513
+ enabled,
514
+ profiles: managedProfiles,
515
+ updatedAt: new Date().toISOString(),
516
+ };
517
+ atomicWriteJson(paths.statePath, nextState);
518
+ if (failedProfiles.length === 0 && managedProfiles.length > 0) {
519
+ cleanupRuntimeGenerations(paths.runtimeRoot, runtimeBundleRoot);
520
+ }
521
+ const failureReason = pluginManagerFailureReason(failedProfiles);
522
+
523
+ return {
524
+ ok: failedProfiles.length === 0,
525
+ action: "dsh-plugin-install",
526
+ runtime: RUNTIME,
527
+ installed: failedProfiles.length === 0 && managedProfiles.length > 0,
528
+ enabled,
529
+ managed: true,
530
+ detectedProfiles: profiles.map((profile) => profile.name),
531
+ dshVersion: compatibility.dshVersion,
532
+ dshVersionTested: compatibility.dshVersionTested,
533
+ testedDshVersions: [...DSH_TESTED_VERSIONS],
534
+ installedProfiles,
535
+ failedProfiles,
536
+ ...(failureReason ? { reason: failureReason } : {}),
537
+ };
538
+ }
539
+
540
+ function rollbackDshPluginReconciliation(paths, options, state, mutatedProfiles, dshCommand) {
541
+ const previouslyManaged = new Set(state.profiles);
542
+ const previousPackageName = runtimeAdapterPackageName(state.runtimeBundleRoot)
543
+ ?? ADAPTER_PACKAGE_NAME;
544
+ const replacementPackageNames = MANAGED_ADAPTER_PACKAGE_NAMES
545
+ .filter((packageName) => packageName !== previousPackageName);
546
+ const rollbackFailedProfiles = [];
547
+ const residualProfiles = [];
548
+ const managedMutationResults = new Map();
549
+ const recordFailure = (failure) => {
550
+ if (!rollbackFailedProfiles.some(({ name }) => name === failure.name)) {
551
+ rollbackFailedProfiles.push(failure);
552
+ }
553
+ };
554
+ for (const name of [...new Set(mutatedProfiles)]) {
555
+ const profilePath = join(paths.profilesRoot, name);
556
+ const before = inspectProfile(name, profilePath);
557
+ if (previouslyManaged.has(name)) {
558
+ const result = runDsh(options, paths, [
559
+ "plugin",
560
+ "--profile",
561
+ name,
562
+ "add",
563
+ `file:${state.runtimeBundleRoot}`,
564
+ ], dshCommand);
565
+ managedMutationResults.set(name, result);
566
+ const restored = inspectProfile(name, profilePath);
567
+ if (result.status === 0
568
+ && !result.error
569
+ && restored.status === "valid"
570
+ && profileHasAdapter(restored.profile, previousPackageName)) {
571
+ const cleanup = removeProfileAdapterPackages(
572
+ paths,
573
+ options,
574
+ name,
575
+ replacementPackageNames,
576
+ dshCommand,
577
+ );
578
+ if (cleanup.failure) recordFailure(cleanup.failure);
579
+ }
580
+ continue;
581
+ }
582
+ if (before.status === "directory_missing"
583
+ || (before.status === "valid" && !profileMentionsAdapter(before.profile))) {
584
+ continue;
585
+ }
586
+ const cleanup = removeProfileAdapterPackages(
587
+ paths,
588
+ options,
589
+ name,
590
+ MANAGED_ADAPTER_PACKAGE_NAMES,
591
+ dshCommand,
592
+ );
593
+ if (cleanup.profile.status !== "directory_missing"
594
+ && (cleanup.profile.status !== "valid"
595
+ || profileMentionsAdapter(cleanup.profile.profile))) {
596
+ residualProfiles.push(name);
597
+ }
598
+ if (cleanup.failure) recordFailure(cleanup.failure);
599
+ }
600
+ const rollbackState = residualProfiles.length > 0
601
+ ? {
602
+ ...state,
603
+ profiles: [...new Set([...state.profiles, ...residualProfiles])].sort(),
604
+ updatedAt: new Date().toISOString(),
605
+ }
606
+ : state;
607
+ const verificationState = rollbackState.enabled
608
+ ? { ...rollbackState, enabled: false }
609
+ : rollbackState;
610
+ atomicWriteJson(paths.statePath, verificationState);
611
+ let authorityRestored = true;
612
+ for (const name of state.profiles) {
613
+ const profile = inspectProfile(name, join(paths.profilesRoot, name));
614
+ if (profile.status === "valid"
615
+ && profileHasInstalledAdapter(
616
+ profile.profile,
617
+ state.runtimeBundleRoot,
618
+ verificationState,
619
+ )
620
+ && !replacementPackageNames.some((packageName) => (
621
+ profileMentionsPackage(profile.profile, packageName)
622
+ ))) {
623
+ continue;
624
+ }
625
+ authorityRestored = false;
626
+ recordFailure(profileMutationFailure(
627
+ name,
628
+ managedMutationResults.get(name) ?? { status: 0 },
629
+ profile,
630
+ "dsh_bundle_not_restored",
631
+ ));
632
+ }
633
+ if (authorityRestored) atomicWriteJson(paths.statePath, rollbackState);
634
+ return { authorityRestored, failedProfiles: rollbackFailedProfiles };
635
+ }
636
+
637
+ function activateDshPluginInstallationUnlocked(paths, options) {
638
+ const state = readAdapterState(paths.statePath);
639
+ const stateProblem = validateState(state, paths);
640
+ if (stateProblem) return { ...stateProblem, action: "dsh-plugin-activate" };
641
+ if (!state) return notManaged(paths, "dsh-plugin-activate");
642
+ const profiles = discoverDshProfiles({ ...options, dshHome: paths.dshHome });
643
+ const profileByName = new Map(profiles.map((profile) => [profile.name, profile]));
644
+ if (state.profiles.length === 0
645
+ || state.profiles.some((name) => (
646
+ !profileHasInstalledAdapter(profileByName.get(name), state.runtimeBundleRoot, state)
647
+ ))) {
648
+ return {
649
+ ok: false,
650
+ action: "dsh-plugin-activate",
651
+ runtime: RUNTIME,
652
+ reason: "managed_profiles_not_installed",
653
+ };
654
+ }
655
+ const nextState = { ...state, enabled: true, updatedAt: new Date().toISOString() };
656
+ atomicWriteJson(paths.statePath, nextState);
657
+ return {
658
+ ok: true,
659
+ action: "dsh-plugin-activate",
660
+ runtime: RUNTIME,
661
+ installed: true,
662
+ enabled: true,
663
+ managed: true,
664
+ profiles: [...state.profiles],
665
+ };
666
+ }
667
+
668
+ function quiesceDshPluginInstallationUnlocked(paths) {
669
+ const state = readAdapterState(paths.statePath);
670
+ const stateProblem = validateState(state, paths);
671
+ if (stateProblem) return { ...stateProblem, action: "dsh-plugin-quiesce" };
672
+ if (!state) return notManaged(paths, "dsh-plugin-quiesce");
673
+ const nextState = disabledState(state, state.profiles);
674
+ atomicWriteJson(paths.statePath, nextState);
675
+ return {
676
+ ok: true,
677
+ action: "dsh-plugin-quiesce",
678
+ runtime: RUNTIME,
679
+ installed: state.profiles.length > 0,
680
+ enabled: false,
681
+ managed: true,
682
+ authorityEnabled: false,
683
+ previouslyEnabled: state.enabled === true,
684
+ revision: nextState.updatedAt,
685
+ profiles: [...state.profiles],
686
+ };
687
+ }
688
+
689
+ function disableDshPluginInstallationUnlocked(paths, options, removeState) {
690
+ const state = readAdapterState(paths.statePath);
691
+ const action = removeState ? "dsh-plugin-remove" : "dsh-plugin-disable";
692
+ const stateProblem = validateState(state, paths);
693
+ if (stateProblem) return { ...stateProblem, action };
694
+ if (!state) return notManaged(paths, action);
695
+
696
+ const disabled = disabledState(state, state.profiles);
697
+ atomicWriteJson(paths.statePath, disabled);
698
+ const dshCommand = resolveDshCommand(options, paths, state);
699
+ const removedProfiles = [];
700
+ const failedProfiles = [];
701
+ for (const name of state.profiles) {
702
+ const before = inspectProfile(name, join(paths.profilesRoot, name));
703
+ if (before.status === "directory_missing") {
704
+ removedProfiles.push(name);
705
+ continue;
706
+ }
707
+ if (before.status === "manifest_unreadable") {
708
+ failedProfiles.push(profileManifestFailure(name));
709
+ continue;
710
+ }
711
+ if (!profileMentionsAdapter(before.profile)) {
712
+ removedProfiles.push(name);
713
+ continue;
714
+ }
715
+ const cleanup = removeProfileAdapterPackages(
716
+ paths,
717
+ options,
718
+ name,
719
+ MANAGED_ADAPTER_PACKAGE_NAMES,
720
+ dshCommand,
721
+ );
722
+ if (cleanup.failure) failedProfiles.push(cleanup.failure);
723
+ else removedProfiles.push(name);
724
+ }
725
+
726
+ if (failedProfiles.length > 0) {
727
+ atomicWriteJson(paths.statePath, disabledState(disabled, failedProfiles.map((profile) => profile.name).sort()));
728
+ const failureReason = pluginManagerFailureReason(failedProfiles);
729
+ return {
730
+ ok: false,
731
+ action,
732
+ runtime: RUNTIME,
733
+ enabled: false,
734
+ removedProfiles,
735
+ failedProfiles,
736
+ ...(failureReason ? { reason: failureReason } : {}),
737
+ };
738
+ }
739
+
740
+ if (removeState) {
741
+ rmSync(paths.statePath, { force: true });
742
+ rmSync(paths.runtimeRoot, { recursive: true, force: true });
743
+ }
744
+ else atomicWriteJson(paths.statePath, disabledState(disabled, []));
745
+ return {
746
+ ok: true,
747
+ action,
748
+ runtime: RUNTIME,
749
+ removed: removeState,
750
+ installed: false,
751
+ enabled: false,
752
+ managed: !removeState,
753
+ removedProfiles,
754
+ };
755
+ }
756
+
757
+ function removeProfileAdapterPackages(paths, options, name, packageNames, dshCommand) {
758
+ const profilePath = join(paths.profilesRoot, name);
759
+ let profile = inspectProfile(name, profilePath);
760
+ let failure;
761
+ for (const packageName of packageNames) {
762
+ if (profile.status === "directory_missing") break;
763
+ if (profile.status !== "valid") {
764
+ failure ??= profileManifestFailure(name);
765
+ break;
766
+ }
767
+ if (!profileMentionsPackage(profile.profile, packageName)) continue;
768
+ const result = runDsh(
769
+ options,
770
+ paths,
771
+ ["plugin", "--profile", name, "remove", packageName],
772
+ dshCommand,
773
+ );
774
+ profile = inspectProfile(name, profilePath);
775
+ if (result.status !== 0
776
+ || result.error
777
+ || (profile.status !== "directory_missing"
778
+ && (profile.status !== "valid"
779
+ || profileMentionsPackage(profile.profile, packageName)))) {
780
+ failure ??= profileMutationFailure(
781
+ name,
782
+ result,
783
+ profile,
784
+ "dsh_bundle_not_removed",
785
+ );
786
+ }
787
+ }
788
+ if (!failure
789
+ && profile.status !== "directory_missing"
790
+ && (profile.status !== "valid"
791
+ || packageNames.some((packageName) => (
792
+ profileMentionsPackage(profile.profile, packageName)
793
+ )))) {
794
+ failure = profileMutationFailure(name, { status: 0 }, profile, "dsh_bundle_not_removed");
795
+ }
796
+ return { profile, failure };
797
+ }
798
+
799
+ function materializeRuntimeBundle(paths, metadata) {
800
+ const manifest = readJsonObject(join(paths.adapterRoot, "package.json"));
801
+ if (manifest?.name !== ADAPTER_PACKAGE_NAME
802
+ || !nonEmpty(manifest.version)
803
+ || manifest.main !== "src/index.mjs"
804
+ || !isDeepStrictEqual(manifest.exports, { ".": "./src/index.mjs" })
805
+ || !isDeepStrictEqual(manifest.files, PROFILE_BUNDLE_FILES)) {
806
+ throw new Error("MemoraX Code DSH adapter source manifest is invalid");
807
+ }
808
+
809
+ const sourceFiles = ["package.json", ...PROFILE_BUNDLE_FILES]
810
+ .filter((relativePath) => relativePath !== PACKAGE_METADATA_FILE)
811
+ .map((relativePath) => {
812
+ const path = bundleSourcePath(paths, relativePath);
813
+ if (!lstatSync(path).isFile()) {
814
+ throw new Error(`MemoraX Code DSH runtime source is not a file: ${relativePath}`);
815
+ }
816
+ return { relativePath, path, content: readFileSync(path) };
817
+ });
818
+ const generation = runtimeGenerationId(metadata, sourceFiles);
819
+ const runtimeBundleRoot = join(paths.runtimeRoot, generation);
820
+ const runtimeMetadata = { ...metadata, runtimeBundleRoot };
821
+ if (runtimeBundleMatches(runtimeBundleRoot, runtimeMetadata, sourceFiles)) {
822
+ return runtimeBundleRoot;
823
+ }
824
+
825
+ mkdirSync(paths.runtimeRoot, { recursive: true, mode: 0o700 });
826
+ rmSync(runtimeBundleRoot, { recursive: true, force: true });
827
+ const temporaryRoot = join(paths.runtimeRoot, `.${generation}.${randomUUID()}.tmp`);
828
+ try {
829
+ mkdirSync(temporaryRoot, { mode: 0o700 });
830
+ for (const { relativePath, path: sourcePath } of sourceFiles) {
831
+ const destinationPath = join(temporaryRoot, relativePath);
832
+ mkdirSync(dirname(destinationPath), { recursive: true, mode: 0o700 });
833
+ copyFileSync(sourcePath, destinationPath);
834
+ }
835
+ atomicWriteJson(join(temporaryRoot, PACKAGE_METADATA_FILE), runtimeMetadata);
836
+ renameSync(temporaryRoot, runtimeBundleRoot);
837
+ return runtimeBundleRoot;
838
+ } catch (error) {
839
+ rmSync(temporaryRoot, { recursive: true, force: true });
840
+ throw error;
841
+ }
842
+ }
843
+
844
+ function runtimeGenerationId(metadata, sourceFiles) {
845
+ const hash = createHash("sha256");
846
+ hash.update(JSON.stringify(metadata));
847
+ for (const { relativePath, content } of sourceFiles) {
848
+ hash.update("\0");
849
+ hash.update(relativePath);
850
+ hash.update("\0");
851
+ hash.update(content);
852
+ }
853
+ return hash.digest("hex");
854
+ }
855
+
856
+ function runtimeBundleMatches(root, metadata, sourceFiles) {
857
+ try {
858
+ if (!lstatSync(root).isDirectory()
859
+ || !isDeepStrictEqual(readJsonObject(join(root, PACKAGE_METADATA_FILE)), metadata)) {
860
+ return false;
861
+ }
862
+ return sourceFiles.every(({ relativePath, content }) => {
863
+ const path = join(root, relativePath);
864
+ return lstatSync(path).isFile() && readFileSync(path).equals(content);
865
+ });
866
+ } catch {
867
+ return false;
868
+ }
869
+ }
870
+
871
+ function bundleSourcePath(paths, relativePath) {
872
+ const commonPrefix = "memorax-code-adapter-common/src/";
873
+ if (relativePath.startsWith(commonPrefix)) {
874
+ return join(commonRoot, relativePath.slice(commonPrefix.length));
875
+ }
876
+ const skillPrefix = "skills/memorax-code/";
877
+ return relativePath.startsWith(skillPrefix)
878
+ ? join(skillRoot, relativePath.slice(skillPrefix.length))
879
+ : join(paths.adapterRoot, relativePath);
880
+ }
881
+
882
+ function cleanupRuntimeGenerations(runtimeRoot, activeRoot) {
883
+ let entries;
884
+ try {
885
+ entries = readdirSync(runtimeRoot, { withFileTypes: true });
886
+ } catch {
887
+ return;
888
+ }
889
+ for (const entry of entries) {
890
+ if (!entry.isDirectory()) continue;
891
+ const candidate = resolve(runtimeRoot, entry.name);
892
+ if (candidate === resolve(activeRoot)) continue;
893
+ try {
894
+ rmSync(candidate, { recursive: true, force: true });
895
+ } catch {
896
+ // The active generation is authoritative; stale cleanup is best effort.
897
+ }
898
+ }
899
+ }
900
+
901
+ function resolvePaths(options) {
902
+ const env = options.env ?? process.env;
903
+ const homeDir = options.homeDir ?? homedir();
904
+ const memoraxCodeHome = resolveHomePath(
905
+ options.memoraxCodeHome ?? nonEmpty(env.MEMORAX_CODE_HOME) ?? join(homeDir, ".memorax-code"),
906
+ homeDir,
907
+ );
908
+ const adapterRoot = resolve(options.adapterRoot ?? ADAPTER_ROOT);
909
+ const statePath = join(memoraxCodeHome, "adapters", RUNTIME, "state.json");
910
+ const runtimeRoot = join(memoraxCodeHome, "adapters", RUNTIME, "runtime", "generations");
911
+ const configuredDshHome = options.dshHome ?? nonEmpty(env.DSH_HOME);
912
+ const dshHome = configuredDshHome === undefined
913
+ ? persistedDshHome({ statePath, memoraxCodeHome, adapterRoot, runtimeRoot }, homeDir)
914
+ ?? resolveHomePath(join(homeDir, ".dsh"), homeDir)
915
+ : resolveHomePath(configuredDshHome, homeDir);
916
+ return {
917
+ env,
918
+ dshHome,
919
+ memoraxCodeHome,
920
+ adapterRoot,
921
+ runtimeRoot,
922
+ profilesRoot: join(dshHome, "profiles"),
923
+ statePath,
924
+ };
925
+ }
926
+
927
+ function persistedDshHome(paths, homeDir) {
928
+ const state = readAdapterState(paths.statePath);
929
+ const value = nonEmpty(state?.dshHome);
930
+ if (!value) return undefined;
931
+ const dshHome = resolveHomePath(value, homeDir);
932
+ return validateState(state, { ...paths, dshHome }) ? undefined : dshHome;
933
+ }
934
+
935
+ function validateState(state, paths) {
936
+ if (!state) return undefined;
937
+ if (state.unreadable) return { ok: false, runtime: RUNTIME, reason: "state_unreadable", statePath: paths.statePath };
938
+ if (state.version !== STATE_VERSION
939
+ || state.runtime !== RUNTIME
940
+ || state.integration !== "plugin"
941
+ || typeof state.enabled !== "boolean"
942
+ || resolve(state.dshHome ?? "") !== paths.dshHome
943
+ || resolve(state.memoraxCodeHome ?? "") !== paths.memoraxCodeHome
944
+ || typeof state.adapterRoot !== "string"
945
+ || !isPathInside(state.runtimeBundleRoot, paths.runtimeRoot)
946
+ || typeof state.memoraxCodeCommand !== "string"
947
+ || typeof state.dshCommand !== "string"
948
+ || !parseDshVersion(state.dshVersion)
949
+ || !timestampString(state.updatedAt)
950
+ || !Array.isArray(state.profiles)
951
+ || !state.profiles.every(validProfileName)) {
952
+ return { ok: false, runtime: RUNTIME, reason: "state_invalid", statePath: paths.statePath };
953
+ }
954
+ return undefined;
955
+ }
956
+
957
+ function disabledState(state, profiles) {
958
+ return {
959
+ ...state,
960
+ enabled: false,
961
+ profiles,
962
+ updatedAt: new Date().toISOString(),
963
+ };
964
+ }
965
+
966
+ function notManaged(paths, action) {
967
+ return {
968
+ ok: true,
969
+ action,
970
+ runtime: RUNTIME,
971
+ installed: false,
972
+ enabled: false,
973
+ managed: false,
974
+ skipped: true,
975
+ reason: "not_managed",
976
+ };
977
+ }
978
+
979
+ function resolveMemoraxCodeCommand(value) {
980
+ const configured = nonEmpty(value);
981
+ const stagedCommand = resolve(ADAPTER_ROOT, "..", "..", "bin", "memorax-code.mjs");
982
+ const sourceCommand = resolve(
983
+ ADAPTER_ROOT,
984
+ "..",
985
+ "..",
986
+ "npm",
987
+ "memorax-code",
988
+ "bin",
989
+ "memorax-code.mjs",
990
+ );
991
+ return configured && !configured.includes("/") && !configured.includes("\\")
992
+ ? configured
993
+ : resolve(configured ?? (existsSync(stagedCommand) ? stagedCommand : sourceCommand));
994
+ }
995
+
996
+ function resolveDshCommand(options, paths, state) {
997
+ const command = nonEmpty(options.dshCommand)
998
+ ?? nonEmpty(paths.env.MEMORAX_CODE_DSH_COMMAND)
999
+ ?? nonEmpty(state?.dshCommand)
1000
+ ?? "dsh";
1001
+ return command.includes("/") || command.includes("\\") ? resolve(command) : command;
1002
+ }
1003
+
1004
+ function runDsh(options, paths, args, command) {
1005
+ const env = { ...paths.env, DSH_HOME: paths.dshHome };
1006
+ let executable;
1007
+ try {
1008
+ executable = resolveWindowsCliInvocation(command, args, {
1009
+ ...options.windowsCliResolution,
1010
+ env,
1011
+ });
1012
+ } catch (error) {
1013
+ return { status: 1, error };
1014
+ }
1015
+ const invocation = {
1016
+ command: executable.command,
1017
+ args: executable.args,
1018
+ // The install watchdog may run a preloaded cleanup after npm has already
1019
+ // removed the adapter files. DSH plugin removal itself only needs DSH_HOME.
1020
+ cwd: existsSync(paths.adapterRoot) ? paths.adapterRoot : paths.dshHome,
1021
+ env,
1022
+ timeout: args.length === 1 && args[0] === "--version"
1023
+ ? DSH_VERSION_TIMEOUT_MS
1024
+ : DEFAULT_COMMAND_TIMEOUT_MS,
1025
+ };
1026
+ if (typeof options.runDsh === "function") {
1027
+ try {
1028
+ return options.runDsh(invocation) ?? { status: 1 };
1029
+ } catch (error) {
1030
+ return { status: 1, error };
1031
+ }
1032
+ }
1033
+ return spawnSync(invocation.command, invocation.args, {
1034
+ cwd: invocation.cwd,
1035
+ env: invocation.env,
1036
+ encoding: "utf8",
1037
+ stdio: ["ignore", "pipe", "pipe"],
1038
+ timeout: invocation.timeout,
1039
+ windowsHide: true,
1040
+ });
1041
+ }
1042
+
1043
+ function inspectDshCompatibility(options, paths, command) {
1044
+ const result = runDsh(options, paths, ["--version"], command);
1045
+ if (result.status !== 0 || result.error) {
1046
+ return {
1047
+ compatible: false,
1048
+ reason: "dsh_version_unavailable",
1049
+ testedDshVersions: [...DSH_TESTED_VERSIONS],
1050
+ };
1051
+ }
1052
+ const output = parseDshVersion(result.stdout);
1053
+ if (!output) {
1054
+ return {
1055
+ compatible: false,
1056
+ reason: "dsh_version_unavailable",
1057
+ testedDshVersions: [...DSH_TESTED_VERSIONS],
1058
+ };
1059
+ }
1060
+ return {
1061
+ compatible: true,
1062
+ dshVersion: output,
1063
+ dshVersionTested: isTestedDshVersion(output),
1064
+ testedDshVersions: [...DSH_TESTED_VERSIONS],
1065
+ };
1066
+ }
1067
+
1068
+ function commandFailure(name, result, contractReason) {
1069
+ return {
1070
+ name,
1071
+ reason: contractReason
1072
+ ? contractReason
1073
+ : /pnpm not found on PATH/i.test(String(result.stderr ?? ""))
1074
+ ? "pnpm_not_found"
1075
+ : result.error?.code === "ENOENT"
1076
+ ? "dsh_not_found"
1077
+ : "dsh_command_failed",
1078
+ status: Number.isInteger(result.status) ? result.status : undefined,
1079
+ };
1080
+ }
1081
+
1082
+ function pluginManagerFailureReason(failures) {
1083
+ return failures.some((failure) => failure.reason === "pnpm_not_found")
1084
+ ? "pnpm_not_found"
1085
+ : undefined;
1086
+ }
1087
+
1088
+ function managedProfileManifestProblem(claimedProfiles) {
1089
+ const profiles = claimedProfiles
1090
+ .filter((profile) => profile.status === "manifest_unreadable")
1091
+ .map((profile) => profile.name);
1092
+ return profiles.length > 0
1093
+ ? {
1094
+ ok: false,
1095
+ action: "dsh-plugin-install",
1096
+ runtime: RUNTIME,
1097
+ reason: "profile_manifest_unreadable",
1098
+ profiles,
1099
+ }
1100
+ : undefined;
1101
+ }
1102
+
1103
+ function profileManifestFailure(name) {
1104
+ return { name, reason: "profile_manifest_unreadable" };
1105
+ }
1106
+
1107
+ function profileMutationFailure(name, result, profile, contractReason) {
1108
+ return result.status === 0 && !result.error && profile.status === "manifest_unreadable"
1109
+ ? profileManifestFailure(name)
1110
+ : commandFailure(name, result, result.status === 0 ? contractReason : undefined);
1111
+ }
1112
+
1113
+ function readProfile(name, path) {
1114
+ const result = inspectProfile(name, path);
1115
+ return result.status === "valid" ? result.profile : undefined;
1116
+ }
1117
+
1118
+ function inspectProfile(name, path) {
1119
+ try {
1120
+ if (!lstatSync(path).isDirectory()) return { status: "manifest_unreadable", name };
1121
+ } catch (error) {
1122
+ return { status: error?.code === "ENOENT" ? "directory_missing" : "manifest_unreadable", name };
1123
+ }
1124
+ try {
1125
+ const manifest = JSON.parse(readFileSync(join(path, "package.json"), "utf8"));
1126
+ const bundles = manifest?.dsh?.profile?.bundles;
1127
+ if (!Array.isArray(bundles) || !bundles.every((value) => typeof value === "string")) {
1128
+ return { status: "manifest_unreadable", name };
1129
+ }
1130
+ return {
1131
+ status: "valid",
1132
+ name,
1133
+ profile: {
1134
+ name,
1135
+ path,
1136
+ dependencies: manifest.dependencies && typeof manifest.dependencies === "object"
1137
+ ? manifest.dependencies
1138
+ : {},
1139
+ bundles,
1140
+ },
1141
+ };
1142
+ } catch {
1143
+ return { status: "manifest_unreadable", name };
1144
+ }
1145
+ }
1146
+
1147
+ function profileMentionsAdapter(profile) {
1148
+ return MANAGED_ADAPTER_PACKAGE_NAMES.some((packageName) => (
1149
+ profileMentionsPackage(profile, packageName)
1150
+ ));
1151
+ }
1152
+
1153
+ function profileMentionsPackage(profile, packageName) {
1154
+ return Boolean(profile
1155
+ && (Object.hasOwn(profile.dependencies, packageName)
1156
+ || profile.bundles.includes(packageName)));
1157
+ }
1158
+
1159
+ function profileHasAdapter(profile, packageName = ADAPTER_PACKAGE_NAME) {
1160
+ return Boolean(profile
1161
+ && Object.hasOwn(profile.dependencies, packageName)
1162
+ && profile.bundles.includes(packageName));
1163
+ }
1164
+
1165
+ function profileHasInstalledAdapter(
1166
+ profile,
1167
+ runtimeBundleRoot,
1168
+ state,
1169
+ ) {
1170
+ if (!state || !nonEmpty(runtimeBundleRoot)) return false;
1171
+ try {
1172
+ const sourceManifest = readJsonObject(join(runtimeBundleRoot, "package.json"));
1173
+ const packageName = sourceManifest?.name;
1174
+ if (!MANAGED_ADAPTER_PACKAGE_NAMES.includes(packageName)
1175
+ || !profileHasAdapter(profile, packageName)
1176
+ || !nonEmpty(sourceManifest.version)) return false;
1177
+
1178
+ const requireFromProfile = createRequire(join(profile.path, "package.json"));
1179
+ const packageRoot = (requireFromProfile.resolve.paths(packageName) ?? [])
1180
+ .map((searchPath) => join(searchPath, packageName))
1181
+ .find((candidate) => existsSync(join(candidate, "package.json")));
1182
+ if (!packageRoot) return false;
1183
+
1184
+ const installedManifest = readJsonObject(join(packageRoot, "package.json"));
1185
+ const sourcePatch = sourceManifest?.dsh?.bundle?.patch;
1186
+ if (installedManifest?.name !== packageName
1187
+ || installedManifest.version !== sourceManifest.version
1188
+ || installedManifest.main !== sourceManifest.main
1189
+ || !isDeepStrictEqual(installedManifest.exports, sourceManifest.exports)
1190
+ || typeof sourcePatch !== "string"
1191
+ || !sourcePatch
1192
+ || installedManifest?.dsh?.bundle?.patch !== sourcePatch) return false;
1193
+
1194
+ readFileSync(join(packageRoot, sourcePatch), "utf8");
1195
+ readFileSync(requireFromProfile.resolve(packageName), "utf8");
1196
+ const authority = requireDshRuntimeAuthority(packageRoot);
1197
+ return authority.enabled === state.enabled
1198
+ && authority.sourceAdapterRoot === resolve(state.adapterRoot)
1199
+ && authority.runtimeBundleRoot === resolve(state.runtimeBundleRoot)
1200
+ && authority.runtimeBundleRoot === resolve(runtimeBundleRoot)
1201
+ && authority.memoraxCodeHome === resolve(state.memoraxCodeHome)
1202
+ && authority.dshHome === resolve(state.dshHome)
1203
+ && authority.memoraxCodeCommand === state.memoraxCodeCommand
1204
+ && authority.dshCommand === state.dshCommand
1205
+ && authority.dshVersion === state.dshVersion
1206
+ && isDeepStrictEqual(authority.profiles, state.profiles)
1207
+ && authority.revision === state.updatedAt;
1208
+ } catch {
1209
+ return false;
1210
+ }
1211
+ }
1212
+
1213
+ function readJsonObject(path) {
1214
+ const value = JSON.parse(readFileSync(path, "utf8"));
1215
+ return value !== null && typeof value === "object" && !Array.isArray(value)
1216
+ ? value
1217
+ : undefined;
1218
+ }
1219
+
1220
+ function runtimeAdapterPackageName(runtimeBundleRoot) {
1221
+ try {
1222
+ const packageName = readJsonObject(join(runtimeBundleRoot, "package.json"))?.name;
1223
+ return MANAGED_ADAPTER_PACKAGE_NAMES.includes(packageName) ? packageName : undefined;
1224
+ } catch {
1225
+ return undefined;
1226
+ }
1227
+ }
1228
+
1229
+ function projectProfileStatus(
1230
+ discoveredProfiles,
1231
+ managedNames,
1232
+ includeUnmanaged,
1233
+ runtimeBundleRoot,
1234
+ state,
1235
+ ) {
1236
+ const profileByName = new Map(discoveredProfiles.map((profile) => [profile.name, profile]));
1237
+ const names = includeUnmanaged
1238
+ ? new Set([...managedNames, ...profileByName.keys()])
1239
+ : managedNames;
1240
+ return [...names]
1241
+ .sort((left, right) => left.localeCompare(right))
1242
+ .map((name) => {
1243
+ const profile = profileByName.get(name);
1244
+ return {
1245
+ name,
1246
+ ...(includeUnmanaged ? { managed: managedNames.has(name) } : {}),
1247
+ exists: Boolean(profile),
1248
+ installed: profileHasInstalledAdapter(profile, runtimeBundleRoot, state),
1249
+ };
1250
+ });
1251
+ }
1252
+
1253
+ function validProfileName(value) {
1254
+ return typeof value === "string"
1255
+ && value.length > 0
1256
+ && value !== "."
1257
+ && value !== ".."
1258
+ && value !== "node_modules"
1259
+ && !value.includes("/")
1260
+ && !value.includes("\\");
1261
+ }
1262
+
1263
+ function resolveHomePath(value, homeDir) {
1264
+ const normalized = String(value);
1265
+ if (normalized === "~") return resolve(homeDir);
1266
+ if (normalized.startsWith("~/") || normalized.startsWith("~\\")) {
1267
+ return resolve(homeDir, normalized.slice(2));
1268
+ }
1269
+ return resolve(normalized);
1270
+ }
1271
+
1272
+ function nonEmpty(value) {
1273
+ const normalized = String(value ?? "").trim();
1274
+ return normalized || undefined;
1275
+ }
1276
+
1277
+ function timestampString(value) {
1278
+ const normalized = nonEmpty(value);
1279
+ return normalized && Number.isFinite(Date.parse(normalized)) ? normalized : undefined;
1280
+ }
1281
+
1282
+ function isPathInside(value, parent) {
1283
+ if (typeof value !== "string" || !value.trim()) return false;
1284
+ const child = relative(resolve(parent), resolve(value));
1285
+ return child !== ""
1286
+ && child !== ".."
1287
+ && !child.startsWith(`..${sep}`)
1288
+ && !isAbsolute(child);
1289
+ }