@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
@@ -57,7 +57,10 @@ export async function resolveRepositoryMemoryScope(input) {
57
57
  }),
58
58
  };
59
59
  }
60
- const workspaceName = sanitizeWorkspaceName(basename(workspace));
60
+ const localWorkspace = gitRepository.kind === "degraded"
61
+ ? gitRepository.workspaceRoot
62
+ : workspace;
63
+ const workspaceName = sanitizeWorkspaceName(basename(localWorkspace));
61
64
  if (!workspaceName) {
62
65
  return {
63
66
  ok: false,
@@ -69,18 +72,30 @@ export async function resolveRepositoryMemoryScope(input) {
69
72
  ok: true,
70
73
  scope: memoryScope({
71
74
  baseUserId,
72
- repositoryKey: identityKey("workspace-directory", workspace),
75
+ repositoryKey: identityKey("workspace-directory", localWorkspace),
73
76
  repositorySlug: workspaceName,
74
77
  identitySource: "workspace-directory",
75
78
  scopeKind: "local-directory",
76
- boundWorkspaceRoot: workspace,
79
+ fallbackReason: gitRepository.kind === "degraded" ? gitRepository.reason : undefined,
80
+ boundWorkspaceRoot: localWorkspace,
77
81
  }),
78
82
  };
79
83
  }
80
84
  export function repositoryMemoryScopesMatch(left, right) {
81
85
  return left.repositoryKey === right.repositoryKey
82
86
  && left.baseUserId === right.baseUserId
83
- && left.effectiveUserId === right.effectiveUserId;
87
+ && left.effectiveUserId === right.effectiveUserId
88
+ && left.fallbackReason === right.fallbackReason;
89
+ }
90
+ export function repositoryMemoryScopeCanUpgradeFromDegradedGit(previous, current) {
91
+ return previous.scopeKind === "local-directory"
92
+ && previous.identitySource === "workspace-directory"
93
+ && previous.fallbackReason === "git_metadata_invalid"
94
+ && current.scopeKind === "git-repository"
95
+ && current.fallbackReason === undefined
96
+ && previous.baseUserId === current.baseUserId
97
+ && previous.boundWorkspaceRoot !== undefined
98
+ && previous.boundWorkspaceRoot === current.boundWorkspaceRoot;
84
99
  }
85
100
  export async function repositoryMemoryScopeContainsWorkspace(scope, workspaceRoot) {
86
101
  if (!scope.boundWorkspaceRoot || !workspaceRoot?.trim())
@@ -96,6 +111,11 @@ export async function repositoryMemoryScopeContainsWorkspace(scope, workspaceRoo
96
111
  }
97
112
  if (!pathContains(scope.boundWorkspaceRoot, workspace))
98
113
  return false;
114
+ if (scope.scopeKind === "local-directory" && scope.fallbackReason === "git_metadata_invalid") {
115
+ const gitRepository = await resolveGitRepository(workspace);
116
+ return gitRepository.kind === "degraded"
117
+ && identityKey("workspace-directory", gitRepository.workspaceRoot) === scope.repositoryKey;
118
+ }
99
119
  return scope.scopeKind !== "local-directory"
100
120
  || !await hasGitMarkerBetween(workspace, scope.boundWorkspaceRoot);
101
121
  }
@@ -112,6 +132,7 @@ function memoryScope(input) {
112
132
  repositoryName: input.repositorySlug,
113
133
  identitySource: input.identitySource,
114
134
  scopeKind: input.scopeKind,
135
+ ...(input.fallbackReason ? { fallbackReason: input.fallbackReason } : {}),
115
136
  ...(input.boundWorkspaceRoot ? { boundWorkspaceRoot: input.boundWorkspaceRoot } : {}),
116
137
  };
117
138
  }
@@ -134,8 +155,11 @@ async function resolveGitRepository(workspace) {
134
155
  }
135
156
  if (!marker)
136
157
  return { kind: "none" };
158
+ let directDirectoryMarker = false;
137
159
  try {
138
- const gitDir = await resolveGitDir(marker.path);
160
+ const resolvedGitDir = await resolveGitDir(marker.path);
161
+ directDirectoryMarker = resolvedGitDir.directDirectoryMarker;
162
+ const gitDir = resolvedGitDir.path;
139
163
  await validateGitHead(gitDir);
140
164
  const commonDir = await resolveGitCommonDir(gitDir);
141
165
  await validateGitCommonDir(commonDir);
@@ -149,7 +173,14 @@ async function resolveGitRepository(workspace) {
149
173
  workspaceRoot: marker.workspaceRoot,
150
174
  };
151
175
  }
152
- catch {
176
+ catch (error) {
177
+ if (directDirectoryMarker && canFallbackFromDirectGitDirectory(error)) {
178
+ return {
179
+ kind: "degraded",
180
+ reason: "git_metadata_invalid",
181
+ workspaceRoot: marker.workspaceRoot,
182
+ };
183
+ }
153
184
  return { kind: "invalid" };
154
185
  }
155
186
  }
@@ -191,19 +222,27 @@ async function hasGitMarkerBetween(workspace, boundary) {
191
222
  }
192
223
  }
193
224
  async function resolveGitDir(marker) {
194
- if ((await fs.lstat(marker)).isSymbolicLink())
195
- throw new Error("symbolic Git metadata marker is not allowed");
196
- const markerStat = await fs.stat(marker);
197
- if (markerStat.isDirectory())
198
- return await canonicalDirectory(marker);
225
+ const markerStat = await fs.lstat(marker);
226
+ if (markerStat.isSymbolicLink()) {
227
+ throw new GitMetadataValidationError("symbolic Git metadata marker is not allowed");
228
+ }
229
+ if (markerStat.isDirectory()) {
230
+ return {
231
+ path: await canonicalDirectory(marker),
232
+ directDirectoryMarker: true,
233
+ };
234
+ }
199
235
  if (!markerStat.isFile())
200
- throw new Error("invalid Git metadata marker");
236
+ throw new GitMetadataValidationError("invalid Git metadata marker");
201
237
  const line = await readSingleLine(marker, MAX_GIT_POINTER_BYTES);
202
238
  const match = /^gitdir:[ \t]*(.+)$/i.exec(line);
203
239
  const gitDir = match?.[1]?.trim();
204
240
  if (!gitDir)
205
- throw new Error("invalid Git metadata pointer");
206
- return await canonicalDirectory(resolveMetadataPath(dirname(marker), gitDir));
241
+ throw new GitMetadataValidationError("invalid Git metadata pointer");
242
+ return {
243
+ path: await canonicalDirectory(resolveMetadataPath(dirname(marker), gitDir)),
244
+ directDirectoryMarker: false,
245
+ };
207
246
  }
208
247
  async function resolveGitCommonDir(gitDir) {
209
248
  const path = join(gitDir, "commondir");
@@ -217,34 +256,35 @@ async function resolveGitCommonDir(gitDir) {
217
256
  }
218
257
  const commonDir = (await readSingleLine(path, MAX_GIT_POINTER_BYTES)).trim();
219
258
  if (!commonDir)
220
- throw new Error("invalid Git common directory pointer");
259
+ throw new GitMetadataValidationError("invalid Git common directory pointer");
221
260
  return await canonicalDirectory(resolveMetadataPath(gitDir, commonDir));
222
261
  }
223
262
  function resolveMetadataPath(base, value) {
224
263
  if (value.includes("\0"))
225
- throw new Error("invalid Git metadata path");
264
+ throw new GitMetadataValidationError("invalid Git metadata path");
226
265
  return isAbsolute(value) ? value : resolve(base, value);
227
266
  }
228
267
  async function canonicalDirectory(path) {
229
268
  const canonical = await fs.realpath(path);
230
- if (!(await fs.stat(canonical)).isDirectory())
231
- throw new Error("Git metadata path is not a directory");
269
+ if (!(await fs.stat(canonical)).isDirectory()) {
270
+ throw new GitMetadataValidationError("Git metadata path is not a directory");
271
+ }
232
272
  return canonical;
233
273
  }
234
274
  async function validateGitHead(gitDir) {
235
275
  const head = (await readSingleLine(join(gitDir, "HEAD"), MAX_GIT_POINTER_BYTES)).trim();
236
276
  if (!/^ref: refs\/[^\0\r\n]+$/.test(head) && !/^(?:[a-fA-F0-9]{40}|[a-fA-F0-9]{64})$/.test(head)) {
237
- throw new Error("invalid Git HEAD");
277
+ throw new GitMetadataValidationError("invalid Git HEAD");
238
278
  }
239
279
  }
240
280
  async function validateGitCommonDir(commonDir) {
241
281
  if (!(await fs.stat(join(commonDir, "objects"))).isDirectory()) {
242
- throw new Error("invalid Git objects directory");
282
+ throw new GitMetadataValidationError("invalid Git objects directory");
243
283
  }
244
284
  const hasRefs = await isDirectory(join(commonDir, "refs"));
245
285
  const hasReftable = await isDirectory(join(commonDir, "reftable"));
246
286
  if (!hasRefs && !hasReftable)
247
- throw new Error("invalid Git references directory");
287
+ throw new GitMetadataValidationError("invalid Git references directory");
248
288
  }
249
289
  async function isDirectory(path) {
250
290
  try {
@@ -263,17 +303,18 @@ async function readSingleLine(path, maxBytes) {
263
303
  else if (value.endsWith("\n"))
264
304
  value = value.slice(0, -1);
265
305
  if (!value || value.includes("\0") || value.includes("\r") || value.includes("\n")) {
266
- throw new Error("invalid single-line Git metadata");
306
+ throw new GitMetadataValidationError("invalid single-line Git metadata");
267
307
  }
268
308
  return value;
269
309
  }
270
310
  async function readBoundedTextFile(path, maxBytes) {
271
311
  const file = await fs.stat(path);
272
- if (!file.isFile() || file.size > maxBytes)
273
- throw new Error("invalid Git metadata file");
312
+ if (!file.isFile() || file.size > maxBytes) {
313
+ throw new GitMetadataValidationError("invalid Git metadata file");
314
+ }
274
315
  const value = await fs.readFile(path, "utf8");
275
316
  if (Buffer.byteLength(value, "utf8") > maxBytes || value.includes("\0")) {
276
- throw new Error("invalid Git metadata file");
317
+ throw new GitMetadataValidationError("invalid Git metadata file");
277
318
  }
278
319
  return value;
279
320
  }
@@ -306,7 +347,7 @@ function parseDirectRemoteUrls(source) {
306
347
  continue;
307
348
  const assignment = /^[ \t]*([A-Za-z][A-Za-z0-9-]*)[ \t]*(?:=[ \t]*)?(.*)$/.exec(line);
308
349
  if (!assignment)
309
- throw new Error("invalid Git config assignment");
350
+ throw new GitMetadataValidationError("invalid Git config assignment");
310
351
  if (assignment[1]?.toLowerCase() !== "url")
311
352
  continue;
312
353
  remotes.set(remote, parseGitConfigValue(assignment[2] ?? ""));
@@ -328,7 +369,7 @@ function logicalGitConfigLines(source) {
328
369
  }
329
370
  }
330
371
  if (pending)
331
- throw new Error("unterminated Git config continuation");
372
+ throw new GitMetadataValidationError("unterminated Git config continuation");
332
373
  return lines;
333
374
  }
334
375
  function hasUnescapedTrailingBackslash(value) {
@@ -340,7 +381,7 @@ function hasUnescapedTrailingBackslash(value) {
340
381
  function parseGitConfigSection(line) {
341
382
  const match = /^\[[ \t]*([A-Za-z0-9][A-Za-z0-9.-]*)[ \t]*(?:"((?:[^"\\]|\\.)*)")?[ \t]*\](?:[ \t]*[#;].*)?$/.exec(line);
342
383
  if (!match?.[1])
343
- throw new Error("invalid Git config section");
384
+ throw new GitMetadataValidationError("invalid Git config section");
344
385
  if (!match[2] && match[1].includes(".")) {
345
386
  const separator = match[1].indexOf(".");
346
387
  return {
@@ -378,11 +419,11 @@ function parseGitConfigValue(value) {
378
419
  }
379
420
  const trailing = input.slice(index + 1).trim();
380
421
  if (trailing && !trailing.startsWith("#") && !trailing.startsWith(";")) {
381
- throw new Error("invalid Git config value");
422
+ throw new GitMetadataValidationError("invalid Git config value");
382
423
  }
383
424
  return result;
384
425
  }
385
- throw new Error("unterminated Git config value");
426
+ throw new GitMetadataValidationError("unterminated Git config value");
386
427
  }
387
428
  function unescapeGitConfigText(value) {
388
429
  let result = "";
@@ -394,7 +435,7 @@ function unescapeGitConfigText(value) {
394
435
  }
395
436
  const escaped = value[index + 1];
396
437
  if (escaped === undefined)
397
- throw new Error("invalid Git config escape");
438
+ throw new GitMetadataValidationError("invalid Git config escape");
398
439
  result += unescapeGitConfigCharacter(escaped);
399
440
  index += 1;
400
441
  }
@@ -409,7 +450,7 @@ function unescapeGitConfigCharacter(value) {
409
450
  return "\b";
410
451
  if (value === '"' || value === "\\")
411
452
  return value;
412
- throw new Error("invalid Git config escape");
453
+ throw new GitMetadataValidationError("invalid Git config escape");
413
454
  }
414
455
  function selectedRemoteRepositoryName(remotes) {
415
456
  const origin = remotes.get("origin");
@@ -465,7 +506,7 @@ function repositoryNameFromCommonDir(commonDir) {
465
506
  : commonName.replace(/\.git$/i, "");
466
507
  const normalized = sanitizeWorkspaceName(name);
467
508
  if (!normalized)
468
- throw new Error("Git common directory has no usable repository name");
509
+ throw new GitMetadataValidationError("Git common directory has no usable repository name");
469
510
  return normalized;
470
511
  }
471
512
  function identityKey(source, value) {
@@ -488,3 +529,10 @@ function pathContains(root, candidate) {
488
529
  function isNodeErrorCode(error, code) {
489
530
  return Boolean(error && typeof error === "object" && "code" in error && error.code === code);
490
531
  }
532
+ class GitMetadataValidationError extends Error {
533
+ }
534
+ function canFallbackFromDirectGitDirectory(error) {
535
+ return error instanceof GitMetadataValidationError
536
+ || isNodeErrorCode(error, "ENOENT")
537
+ || isNodeErrorCode(error, "ENOTDIR");
538
+ }
@@ -1,217 +1,8 @@
1
1
  #!/usr/bin/env node
2
- import { createServer, } from "node:http";
3
- import { isMainEntrypoint } from "./entrypoint.js";
4
- import { backendDebug } from "./debug-log.js";
5
- import { createMemoryReminderTraceRecorder } from "./memory-reminder-trace-recorder.js";
6
- import { handleMemoryViewerRequest } from "./server-memory-viewer.js";
7
- import { handleMemoryHookRequest } from "./server-memory-hook.js";
8
- import { createBackendMemoryObservability } from "./server-observability.js";
9
- import { createMemoryService } from "./memory-service.js";
10
- import { handleHealthRequest } from "./server-health.js";
11
- import { authorized, memoryViewerSessionCookieHeader, publicErrorMessage, statusCodeFromError } from "./server-http.js";
12
- import { json } from "./server-json.js";
13
- import { createBackendState } from "./backend-state.js";
14
- import { TRACE_CLIENTS } from "./trace-config.js";
15
- import { pruneExpiredTraceSessionsForClient } from "./trace-store.js";
16
- import { startMemoryWritebackReconciler } from "./memory-writeback-reconciler.js";
17
- import { createMemoryWritebackTaskProjection } from "./memory-writeback-task-projection.js";
18
- import { readActiveManagedClients } from "./active-client-selection.js";
19
- const DEFAULT_BACKEND_SHUTDOWN_TIMEOUT_MS = 4_000;
20
- export function createBackendServer(state = createBackendState(), options = {}) {
21
- const memoryEnv = { ...process.env, MEMORAX_CODE_HOME: state.sessionHome };
22
- const memoryWritebackTaskProjections = TRACE_CLIENTS.map((client) => createMemoryWritebackTaskProjection({
23
- memoraxCodeHome: state.sessionHome,
24
- client,
25
- }));
26
- const memoryObservability = createBackendMemoryObservability(state.sessionHome, options.memoryObservability, memoryEnv, memoryWritebackTaskProjections.map((projection) => projection.observabilityHook));
27
- const memoryService = createMemoryService({
28
- diagnosticLogger: backendDebug,
29
- env: memoryEnv,
30
- memoraxCodeHome: state.sessionHome,
31
- memoryObservability,
32
- });
33
- const memoryHookDependencies = {
34
- memoryService,
35
- memoryReminderTraceRecorder: createMemoryReminderTraceRecorder({
36
- diagnosticLogger: backendDebug,
37
- env: memoryEnv,
38
- memoraxCodeHome: state.sessionHome,
39
- }),
40
- };
41
- for (const client of TRACE_CLIENTS) {
42
- void pruneExpiredTraceSessionsForClient({
43
- client,
44
- memoraxCodeHome: state.sessionHome,
45
- }).catch((error) => {
46
- backendDebug(`${client}_trace.retention_cleanup_failed`, {
47
- error: error instanceof Error ? error.message : String(error),
48
- });
49
- });
50
- }
51
- const memoryWritebackReconcilers = memoryWritebackTaskProjections.map((taskProjection) => (startMemoryWritebackReconciler({
52
- memoraxCodeHome: state.sessionHome,
53
- env: memoryEnv,
54
- taskProjection,
55
- })));
56
- const handleRequest = async (req, res) => {
57
- const url = new URL(req.url ?? "/", `http://${req.headers.host ?? "127.0.0.1"}`);
58
- backendDebug("http.request", {
59
- method: req.method,
60
- path: url.pathname,
61
- });
62
- try {
63
- if (req.method === "GET" && url.pathname === "/health")
64
- return handleHealthRequest(state, res);
65
- if (!authorized(state, req, url))
66
- return json(res, 401, { ok: false, error: "unauthorized" });
67
- if (url.pathname === "/memory-viewer"
68
- || url.pathname.startsWith("/memory-viewer/")) {
69
- if (await handleMemoryViewerRequest(url, req, res, {
70
- memoraxCodeHome: state.sessionHome,
71
- claudeProjectsRoot: readActiveManagedClients(state.sessionHome)?.claude === true
72
- ? state.claudeProjectsRoot
73
- : false,
74
- sessionCookie: memoryViewerSessionCookieHeader(state, req, url),
75
- }))
76
- return;
77
- }
78
- if (await handleMemoryHookRequest(memoryHookDependencies, url, req, res))
79
- return;
80
- return json(res, 404, { ok: false, error: "not found" });
81
- }
82
- catch (error) {
83
- const status = statusCodeFromError(error);
84
- const publicMessage = publicErrorMessage(error);
85
- if (status >= 500)
86
- console.error("request failed", error);
87
- if (res.headersSent) {
88
- return res.end();
89
- }
90
- return json(res, status, { ok: false, error: publicMessage });
91
- }
92
- };
93
- const activeRequests = new Set();
94
- const server = createServer((req, res) => {
95
- const request = handleRequest(req, res);
96
- activeRequests.add(request);
97
- void request.then(() => activeRequests.delete(request), () => activeRequests.delete(request));
98
- });
99
- return attachBackendShutdown(server, {
100
- activeRequests,
101
- memoryObservability,
102
- memoryService,
103
- memoryWritebackReconcilers,
104
- timeoutMs: positiveShutdownTimeout(options.shutdownTimeoutMs),
105
- });
106
- }
107
- function attachBackendShutdown(server, resources) {
108
- const closeHttpServer = server.close.bind(server);
109
- const backendServer = server;
110
- let shutdownPromise;
111
- backendServer.shutdown = () => {
112
- shutdownPromise ??= shutdownBackend(backendServer, closeHttpServer, resources);
113
- return shutdownPromise;
114
- };
115
- backendServer.close = ((callback) => {
116
- void backendServer.shutdown().then(() => callback?.(), (error) => callback?.(error instanceof Error ? error : new Error(String(error))));
117
- return backendServer;
118
- });
119
- return backendServer;
120
- }
121
- async function shutdownBackend(server, closeHttpServer, resources) {
122
- const deadline = Date.now() + resources.timeoutMs;
123
- const reconcilerDrain = settleShutdownWork("memory_writeback_reconcilers", Promise.all(resources.memoryWritebackReconcilers.map((reconciler) => reconciler.close())));
124
- try {
125
- await waitForShutdownPhase("http_server", closeBackendHttpServer(server, closeHttpServer, resources.timeoutMs), deadline);
126
- await waitForShutdownPhase("http_requests", waitForActiveRequests(resources.activeRequests), deadline);
127
- if (Date.now() < deadline) {
128
- await waitForShutdownPhase("memory_service", settleShutdownWork("memory_service", resources.memoryService.drain()), deadline);
129
- }
130
- if (Date.now() < deadline && resources.memoryObservability?.drain) {
131
- await waitForShutdownPhase("memory_observability", settleShutdownWork("memory_observability", resources.memoryObservability.drain()), deadline);
132
- }
133
- await waitForShutdownPhase("background_work", reconcilerDrain, deadline);
134
- }
135
- finally {
136
- resources.memoryService.close();
137
- }
138
- }
139
- function closeBackendHttpServer(server, closeHttpServer, timeoutMs) {
140
- return new Promise((resolve, reject) => {
141
- const forceTimer = setTimeout(() => {
142
- backendDebug("shutdown.http_connections_forced", { timeoutMs });
143
- try {
144
- server.closeAllConnections();
145
- }
146
- catch (error) {
147
- backendDebug("shutdown.http_connections_force_failed", {
148
- error: error instanceof Error ? error.message : String(error),
149
- });
150
- }
151
- }, timeoutMs);
152
- const done = (error) => {
153
- clearTimeout(forceTimer);
154
- if (error && error.code !== "ERR_SERVER_NOT_RUNNING") {
155
- reject(error);
156
- return;
157
- }
158
- resolve();
159
- };
160
- try {
161
- closeHttpServer(done);
162
- server.closeIdleConnections();
163
- }
164
- catch (error) {
165
- done(error instanceof Error ? error : new Error(String(error)));
166
- }
167
- });
168
- }
169
- async function waitForActiveRequests(activeRequests) {
170
- while (activeRequests.size > 0) {
171
- await Promise.allSettled([...activeRequests]);
172
- }
173
- }
174
- async function waitForShutdownPhase(phase, work, deadline) {
175
- const remainingMs = deadline - Date.now();
176
- if (remainingMs <= 0) {
177
- backendDebug("shutdown.phase_timed_out", { phase, remainingMs: 0 });
178
- return false;
179
- }
180
- let timer;
181
- const result = await Promise.race([
182
- work.then(() => ({ completed: true }), (error) => ({ completed: true, error })),
183
- new Promise((resolve) => {
184
- timer = setTimeout(() => resolve({ completed: false }), remainingMs);
185
- }),
186
- ]);
187
- if (timer)
188
- clearTimeout(timer);
189
- if (!result.completed) {
190
- backendDebug("shutdown.phase_timed_out", { phase, remainingMs });
191
- return false;
192
- }
193
- if ("error" in result)
194
- throw result.error;
195
- return true;
196
- }
197
- async function settleShutdownWork(label, work) {
198
- try {
199
- await work;
200
- }
201
- catch (error) {
202
- backendDebug("shutdown.work_failed", {
203
- label,
204
- error: error instanceof Error ? error.message : String(error),
205
- });
206
- }
207
- }
208
- function positiveShutdownTimeout(value) {
209
- if (typeof value === "number" && Number.isSafeInteger(value) && value > 0)
210
- return value;
211
- return DEFAULT_BACKEND_SHUTDOWN_TIMEOUT_MS;
212
- }
2
+ import { isMainEntrypoint } from "./entrypoints/main.js";
3
+ export { createBackendServer } from "./app/backend-server.js";
213
4
  if (isMainEntrypoint(import.meta.url)) {
214
- import("./server-cli.js")
5
+ import("./entrypoints/backend-cli.js")
215
6
  .then(({ runBackendCli }) => runBackendCli(process.argv))
216
7
  .catch((error) => {
217
8
  console.error(error instanceof Error ? error.message : String(error));
@@ -1,4 +1,4 @@
1
- import { runBackendCli } from "./server-cli.js";
1
+ import { runBackendCli } from "./entrypoints/backend-cli.js";
2
2
  const markerIndex = process.argv.indexOf("--memorax-code-backend-instance");
3
3
  const instanceId = markerIndex >= 0 ? process.argv[markerIndex + 1] : undefined;
4
4
  if (!instanceId
@@ -1,4 +1,4 @@
1
- import { backendEnv } from "./backend-env.js";
1
+ import { backendEnv } from "../config/backend-env.js";
2
2
  export function backendDebugEnabled() {
3
3
  const value = backendEnv("DEBUG_REQUESTS");
4
4
  return value === "1" || value === "true" || value === "yes";
@@ -0,0 +1,75 @@
1
+ import { open } from "node:fs/promises";
2
+ const JSONL_TAIL_SCAN_CHUNK_BYTES = 8 * 1024;
3
+ const pathOperations = new Map();
4
+ export async function appendRepairingJsonl(path, text) {
5
+ await serializePath(path, async () => {
6
+ const handle = await open(path, "a+", 0o600);
7
+ try {
8
+ const { rollbackSize, separator } = await prepareTailForAppend(handle);
9
+ try {
10
+ await handle.writeFile(`${separator}${text}`, "utf8");
11
+ }
12
+ catch (error) {
13
+ await handle.truncate(rollbackSize).catch(() => undefined);
14
+ throw error;
15
+ }
16
+ }
17
+ finally {
18
+ await handle.close();
19
+ }
20
+ });
21
+ }
22
+ async function serializePath(path, operation) {
23
+ const previous = pathOperations.get(path) ?? Promise.resolve();
24
+ const current = previous.catch(() => undefined).then(operation);
25
+ pathOperations.set(path, current);
26
+ try {
27
+ return await current;
28
+ }
29
+ finally {
30
+ if (pathOperations.get(path) === current)
31
+ pathOperations.delete(path);
32
+ }
33
+ }
34
+ async function prepareTailForAppend(handle) {
35
+ const size = (await handle.stat()).size;
36
+ if (size === 0)
37
+ return { rollbackSize: 0, separator: "" };
38
+ const lastByte = Buffer.allocUnsafe(1);
39
+ await readExactAt(handle, lastByte, size - 1);
40
+ if (lastByte[0] === 0x0a)
41
+ return { rollbackSize: size, separator: "" };
42
+ const tailStart = await jsonlTailStart(handle, size);
43
+ const tail = Buffer.allocUnsafe(size - tailStart);
44
+ await readExactAt(handle, tail, tailStart);
45
+ try {
46
+ JSON.parse(tail.toString("utf8"));
47
+ return { rollbackSize: size, separator: "\n" };
48
+ }
49
+ catch {
50
+ await handle.truncate(tailStart);
51
+ return { rollbackSize: tailStart, separator: "" };
52
+ }
53
+ }
54
+ async function jsonlTailStart(handle, size) {
55
+ let end = size;
56
+ while (end > 0) {
57
+ const start = Math.max(0, end - JSONL_TAIL_SCAN_CHUNK_BYTES);
58
+ const buffer = Buffer.allocUnsafe(end - start);
59
+ await readExactAt(handle, buffer, start);
60
+ const newline = buffer.lastIndexOf(0x0a);
61
+ if (newline >= 0)
62
+ return start + newline + 1;
63
+ end = start;
64
+ }
65
+ return 0;
66
+ }
67
+ async function readExactAt(handle, buffer, position) {
68
+ let offset = 0;
69
+ while (offset < buffer.length) {
70
+ const { bytesRead } = await handle.read(buffer, offset, buffer.length - offset, position + offset);
71
+ if (bytesRead === 0)
72
+ throw new Error("failed to read JSONL tail");
73
+ offset += bytesRead;
74
+ }
75
+ }