@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.
- package/README.md +16 -12
- package/bin/memorax-code-npm-preinstall.mjs +7 -2
- package/bin/memorax-code-opencode.mjs +4 -0
- package/bin/memorax-code-plugin-postinstall.mjs +424 -108
- package/docs/configuration.md +153 -29
- package/docs/troubleshooting.md +93 -7
- package/lib/dsh-plugin-install.mjs +22 -0
- package/lib/memorax-code-adapter-common/src/hooks/capture-cwd-hook.mjs +21 -14
- package/lib/memorax-code-adapter-common/src/hooks/ensure-backend-runner.mjs +26 -7
- package/lib/memorax-code-adapter-common/src/hooks/memory-skill-reminder-hook.mjs +86 -95
- package/lib/memorax-code-adapter-common/src/hooks/memory-skill-reminder-policy.mjs +58 -0
- package/lib/memorax-code-adapter-common/src/repo-memory/repo-memory-auto-build.mjs +38 -0
- package/lib/memorax-code-adapter-common/src/repo-memory/repo-memory-job-supervisor.mjs +1 -1
- package/lib/memorax-code-adapter-common/src/windows-cli-invocation.mjs +13 -1
- package/lib/memorax-code-backend/dist/app/backend-server.js +210 -0
- package/lib/memorax-code-backend/dist/{server-observability.js → app/memory-observability.js} +4 -4
- package/lib/memorax-code-backend/dist/{backend-state.js → app/state.js} +1 -1
- package/lib/memorax-code-backend/dist/{claude-adapter-lifecycle.js → clients/claude/lifecycle.js} +2 -2
- package/lib/memorax-code-backend/dist/{claude-memory-hook-runtime.js → clients/claude/memory-hook-runtime.js} +16 -9
- package/lib/memorax-code-backend/dist/clients/codex/lifecycle.js +131 -0
- package/lib/memorax-code-backend/dist/{codex-memory-hook-runtime.js → clients/codex/memory-hook-runtime.js} +18 -11
- package/lib/memorax-code-backend/dist/{codex-plugin-hooks.js → clients/codex/plugin-hooks.js} +1 -1
- package/lib/memorax-code-backend/dist/{codex-plugin-install.js → clients/codex/plugin-install.js} +6 -6
- package/lib/memorax-code-backend/dist/clients/dsh/lifecycle.js +75 -0
- package/lib/memorax-code-backend/dist/clients/dsh/memory-hook-runtime.js +258 -0
- package/lib/memorax-code-backend/dist/clients/dsh/session-turn.js +249 -0
- package/lib/memorax-code-backend/dist/clients/opencode/lifecycle.js +54 -0
- package/lib/memorax-code-backend/dist/clients/opencode/memory-hook-runtime.js +277 -0
- package/lib/memorax-code-backend/dist/clients/opencode/message-turn.js +78 -0
- package/lib/memorax-code-backend/dist/codex-adapter-lifecycle.js +1 -131
- package/lib/memorax-code-backend/dist/{memorax-code-config.js → config/memorax-code.js} +32 -4
- package/lib/memorax-code-backend/dist/{server-cli.js → entrypoints/backend-cli.js} +157 -34
- package/lib/memorax-code-backend/dist/jsonl-append.js +1 -75
- package/lib/memorax-code-backend/dist/{active-client-selection.js → lifecycle/active-clients.js} +12 -1
- package/lib/memorax-code-backend/dist/{backend-service-cleanup.js → lifecycle/backend/cleanup.js} +1 -1
- package/lib/memorax-code-backend/dist/{backend-service-record.js → lifecycle/backend/record.js} +1 -1
- package/lib/memorax-code-backend/dist/{backend-service-result.js → lifecycle/backend/result.js} +2 -2
- package/lib/memorax-code-backend/dist/{service.js → lifecycle/backend/service.js} +16 -16
- package/lib/memorax-code-backend/dist/{backend-token-record.js → lifecycle/backend/token-record.js} +1 -1
- package/lib/memorax-code-backend/dist/{backend-service-token.js → lifecycle/backend/token.js} +2 -2
- package/lib/memorax-code-backend/dist/lifecycle/client-plugin-removal.js +109 -0
- package/lib/memorax-code-backend/dist/{client-selection.js → lifecycle/client-selection.js} +11 -5
- package/lib/memorax-code-backend/dist/{backend-lifecycle-lock.js → lifecycle/lock.js} +1 -1
- package/lib/memorax-code-backend/dist/{memorax-code-lifecycle.js → lifecycle/orchestrator.js} +325 -39
- package/lib/memorax-code-backend/dist/memorax-cli.js +3 -1
- package/lib/memorax-code-backend/dist/memorax-code.js +1 -1
- package/lib/memorax-code-backend/dist/{automatic-memory-retrieval.js → memory/automatic-retrieval.js} +3 -3
- package/lib/memorax-code-backend/dist/{automatic-memory-writeback.js → memory/automatic-writeback.js} +82 -21
- package/lib/memorax-code-backend/dist/{memory-cli.js → memory/cli.js} +45 -10
- package/lib/memorax-code-backend/dist/{memory-hook-command.js → memory/hook-command.js} +156 -9
- package/lib/memorax-code-backend/dist/memory/observability.js +1 -0
- package/lib/memorax-code-backend/dist/memory/payload-redaction.js +212 -0
- package/lib/memorax-code-backend/dist/{memory-reminder-trace-recorder.js → memory/reminder-trace-recorder.js} +20 -7
- package/lib/memorax-code-backend/dist/{repository-memory-context.js → memory/repository-session.js} +25 -4
- package/lib/memorax-code-backend/dist/{memory-service.js → memory/service.js} +30 -6
- package/lib/memorax-code-backend/dist/{memory-turn-coordinator.js → memory/turn-coordinator.js} +7 -3
- package/lib/memorax-code-backend/dist/{memory-writeback-buffer.js → memory/writeback-buffer.js} +31 -2
- package/lib/memorax-code-backend/dist/{memory-writeback-chunk.js → memory/writeback-chunk.js} +1 -1
- package/lib/memorax-code-backend/dist/{memory-writeback-reconciler.js → memory/writeback-reconciler.js} +6 -6
- package/lib/memorax-code-backend/dist/{memory-writeback-task-projection.js → memory/writeback-task-projection.js} +4 -4
- package/lib/memorax-code-backend/dist/{memorax-adapter.js → provider/memorax/adapter.js} +5 -5
- package/lib/memorax-code-backend/dist/{memorax-config.js → provider/memorax/config.js} +4 -4
- package/lib/memorax-code-backend/dist/{memorax-http.js → provider/memorax/http.js} +1 -1
- package/lib/memorax-code-backend/dist/{repo-memory-readiness.js → repository/readiness.js} +3 -3
- package/lib/memorax-code-backend/dist/{repository-memory-scope.js → repository/scope.js} +81 -33
- package/lib/memorax-code-backend/dist/server.js +3 -212
- package/lib/memorax-code-backend/dist/service-entrypoint.js +1 -1
- package/lib/memorax-code-backend/dist/{debug-log.js → shared/debug-log.js} +1 -1
- package/lib/memorax-code-backend/dist/shared/jsonl-append.js +75 -0
- package/lib/memorax-code-backend/dist/shared/windows-cli-invocation.js +148 -0
- package/lib/memorax-code-backend/dist/{trace-config.js → trace/config.js} +43 -5
- package/lib/memorax-code-backend/dist/{trace-context.js → trace/context.js} +53 -2
- package/lib/memorax-code-backend/dist/{trace-store.js → trace/store.js} +3 -3
- package/lib/memorax-code-backend/dist/{server-health.js → transport/http/health.js} +1 -1
- package/lib/memorax-code-backend/dist/{server-memory-hook.js → transport/http/memory-hook.js} +3 -3
- package/lib/memorax-code-backend/dist/{server-http.js → transport/http/request.js} +1 -1
- package/lib/memorax-code-backend/dist/{claude-local-transcript.js → viewer/history/claude-transcript.js} +3 -3
- package/lib/memorax-code-backend/dist/{memory-viewer-session-title.js → viewer/history/session-title.js} +1 -1
- package/lib/memorax-code-backend/dist/{server-memory-viewer.js → viewer/http/public-routes.js} +25 -14
- package/lib/memorax-code-backend/dist/viewer/model.js +1 -0
- package/lib/memorax-code-backend/dist/{memory-viewer-activity.js → viewer/projection/activity.js} +2 -2
- package/lib/memorax-code-backend/dist/{memory-viewer-history-projection.js → viewer/projection/history.js} +1 -1
- package/lib/memorax-code-backend/dist/{memory-viewer-observability.js → viewer/projection/observability.js} +1 -1
- package/lib/memorax-code-backend/dist/{memory-viewer-user-projection.js → viewer/projection/user.js} +1 -1
- package/lib/memorax-code-backend/dist/{memory-viewer-writeback-status.js → viewer/projection/writeback-status.js} +1 -1
- package/lib/memorax-code-backend/dist/{memory-viewer-store.js → viewer/store.js} +59 -32
- package/lib/memorax-code-backend/dist/viewer/ui/icon.js +1 -0
- package/lib/memorax-code-backend/dist/{memory-viewer-user-html.js → viewer/ui/user-html.js} +14 -12
- package/lib/memorax-code-backend/dist/windows-cli-invocation.js +1 -148
- package/lib/memorax-code-backend/package.json +3 -3
- package/lib/memorax-code-claude-adapter/.claude-plugin/plugin.json +1 -1
- package/lib/memorax-code-claude-adapter/hooks/runtime-shell.json +1 -1
- package/lib/memorax-code-claude-adapter/package.json +1 -1
- package/lib/memorax-code-claude-adapter/runtime-hooks/memory-turn.mjs +5 -0
- package/lib/memorax-code-claude-adapter/skills/memorax-code/SKILL.md +23 -15
- package/lib/memorax-code-claude-adapter/skills/memorax-code/defaults.json +8 -5
- package/lib/memorax-code-claude-adapter/skills/memorax-code/references/memorax-add.md +5 -1
- package/lib/memorax-code-claude-adapter/skills/memorax-code/references/memorax-search.md +40 -10
- package/lib/memorax-code-claude-adapter/skills/memorax-code/references/personal-read.md +1 -1
- package/lib/memorax-code-claude-adapter/skills/memorax-code/references/personal-write.md +33 -13
- package/lib/memorax-code-claude-adapter/skills/memorax-code/references/repo-build.md +62 -13
- package/lib/memorax-code-claude-adapter/skills/memorax-code/references/repo-read.md +11 -4
- package/lib/memorax-code-claude-adapter/skills/memorax-code/references/repo-templates.md +179 -59
- package/lib/memorax-code-claude-adapter/skills/memorax-code/references/repo-update.md +18 -7
- package/lib/memorax-code-claude-adapter/skills/memorax-code/scripts/collect_all.py +122 -39
- package/lib/memorax-code-claude-adapter/skills/memorax-code/scripts/detect_updates.py +73 -10
- package/lib/memorax-code-claude-adapter/skills/memorax-code/scripts/github_resource_facets.py +9 -1
- package/lib/memorax-code-claude-adapter/skills/memorax-code/scripts/gitlab_resource_facets.py +9 -1
- package/lib/memorax-code-claude-adapter/skills/memorax-code/scripts/validate_memory.py +23 -1
- package/lib/memorax-code-claude-adapter/src/plugin-install.mjs +2 -0
- package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/.claude-plugin/plugin.json +1 -1
- package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/hooks/runtime-shell.json +1 -1
- package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/memorax-code-adapter-common/src/hooks/capture-cwd-hook.mjs +21 -14
- package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/memorax-code-adapter-common/src/hooks/ensure-backend-runner.mjs +26 -7
- package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/memorax-code-adapter-common/src/hooks/memory-skill-reminder-hook.mjs +86 -95
- package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/memorax-code-adapter-common/src/hooks/memory-skill-reminder-policy.mjs +58 -0
- 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
- 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
- package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/memorax-code-adapter-common/src/windows-cli-invocation.mjs +13 -1
- package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/package.json +1 -1
- package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/runtime-hooks/memory-turn.mjs +5 -0
- package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/skills/memorax-code/SKILL.md +23 -15
- package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/skills/memorax-code/defaults.json +8 -5
- package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/skills/memorax-code/references/memorax-add.md +5 -1
- package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/skills/memorax-code/references/memorax-search.md +40 -10
- package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/skills/memorax-code/references/personal-read.md +1 -1
- package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/skills/memorax-code/references/personal-write.md +33 -13
- package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/skills/memorax-code/references/repo-build.md +62 -13
- package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/skills/memorax-code/references/repo-read.md +11 -4
- package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/skills/memorax-code/references/repo-templates.md +179 -59
- package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/skills/memorax-code/references/repo-update.md +18 -7
- package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/skills/memorax-code/scripts/collect_all.py +122 -39
- package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/skills/memorax-code/scripts/detect_updates.py +73 -10
- package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/skills/memorax-code/scripts/github_resource_facets.py +9 -1
- package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/skills/memorax-code/scripts/gitlab_resource_facets.py +9 -1
- package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/skills/memorax-code/scripts/validate_memory.py +23 -1
- package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/src/plugin-install.mjs +2 -0
- package/lib/memorax-code-codex-adapter/.codex-plugin/plugin.json +1 -1
- package/lib/memorax-code-codex-adapter/hooks/runtime-shell.json +1 -1
- package/lib/memorax-code-codex-adapter/package.json +1 -1
- package/lib/memorax-code-codex-adapter/runtime-hooks/memory-skill-reminder.mjs +16 -2
- package/lib/memorax-code-codex-adapter/skills/memorax-code/SKILL.md +23 -15
- package/lib/memorax-code-codex-adapter/skills/memorax-code/defaults.json +8 -5
- package/lib/memorax-code-codex-adapter/skills/memorax-code/references/memorax-add.md +5 -1
- package/lib/memorax-code-codex-adapter/skills/memorax-code/references/memorax-search.md +40 -10
- package/lib/memorax-code-codex-adapter/skills/memorax-code/references/personal-read.md +1 -1
- package/lib/memorax-code-codex-adapter/skills/memorax-code/references/personal-write.md +33 -13
- package/lib/memorax-code-codex-adapter/skills/memorax-code/references/repo-build.md +62 -13
- package/lib/memorax-code-codex-adapter/skills/memorax-code/references/repo-read.md +11 -4
- package/lib/memorax-code-codex-adapter/skills/memorax-code/references/repo-templates.md +179 -59
- package/lib/memorax-code-codex-adapter/skills/memorax-code/references/repo-update.md +18 -7
- package/lib/memorax-code-codex-adapter/skills/memorax-code/scripts/collect_all.py +122 -39
- package/lib/memorax-code-codex-adapter/skills/memorax-code/scripts/detect_updates.py +73 -10
- package/lib/memorax-code-codex-adapter/skills/memorax-code/scripts/github_resource_facets.py +9 -1
- package/lib/memorax-code-codex-adapter/skills/memorax-code/scripts/gitlab_resource_facets.py +9 -1
- package/lib/memorax-code-codex-adapter/skills/memorax-code/scripts/validate_memory.py +23 -1
- package/lib/memorax-code-dsh-adapter/cordis.patch.yml +10 -0
- package/lib/memorax-code-dsh-adapter/hooks/repo-memory-job.mjs +68 -0
- package/lib/memorax-code-dsh-adapter/package.json +69 -0
- package/lib/memorax-code-dsh-adapter/skills/memorax-code/SKILL.md +91 -0
- package/lib/memorax-code-dsh-adapter/skills/memorax-code/agents/claude.yaml +10 -0
- package/lib/memorax-code-dsh-adapter/skills/memorax-code/agents/openai.yaml +7 -0
- package/lib/memorax-code-dsh-adapter/skills/memorax-code/defaults.json +12 -0
- package/lib/memorax-code-dsh-adapter/skills/memorax-code/references/memorax-add.md +86 -0
- package/lib/memorax-code-dsh-adapter/skills/memorax-code/references/memorax-search.md +91 -0
- package/lib/memorax-code-dsh-adapter/skills/memorax-code/references/personal-read.md +46 -0
- package/lib/memorax-code-dsh-adapter/skills/memorax-code/references/personal-write.md +120 -0
- package/lib/memorax-code-dsh-adapter/skills/memorax-code/references/repo-build.md +319 -0
- package/lib/memorax-code-dsh-adapter/skills/memorax-code/references/repo-read.md +103 -0
- package/lib/memorax-code-dsh-adapter/skills/memorax-code/references/repo-templates.md +390 -0
- package/lib/memorax-code-dsh-adapter/skills/memorax-code/references/repo-update.md +127 -0
- package/lib/memorax-code-dsh-adapter/skills/memorax-code/scripts/collect_all.py +579 -0
- package/lib/memorax-code-dsh-adapter/skills/memorax-code/scripts/detect_updates.py +919 -0
- package/lib/memorax-code-dsh-adapter/skills/memorax-code/scripts/git_commit_facets.py +222 -0
- package/lib/memorax-code-dsh-adapter/skills/memorax-code/scripts/github_resource_facets.py +512 -0
- package/lib/memorax-code-dsh-adapter/skills/memorax-code/scripts/gitlab_resource_facets.py +517 -0
- package/lib/memorax-code-dsh-adapter/skills/memorax-code/scripts/prepare_repo_memory.py +411 -0
- package/lib/memorax-code-dsh-adapter/skills/memorax-code/scripts/user_profile_memory.py +528 -0
- package/lib/memorax-code-dsh-adapter/skills/memorax-code/scripts/validate_memory.py +248 -0
- package/lib/memorax-code-dsh-adapter/src/backend-client.mjs +119 -0
- package/lib/memorax-code-dsh-adapter/src/dsh-message.mjs +32 -0
- package/lib/memorax-code-dsh-adapter/src/dsh-version.mjs +18 -0
- package/lib/memorax-code-dsh-adapter/src/http-client.mjs +55 -0
- package/lib/memorax-code-dsh-adapter/src/index.mjs +72 -0
- package/lib/memorax-code-dsh-adapter/src/personal-context-worker.mjs +48 -0
- package/lib/memorax-code-dsh-adapter/src/personal-context.mjs +114 -0
- package/lib/memorax-code-dsh-adapter/src/plugin.mjs +724 -0
- package/lib/memorax-code-dsh-adapter/src/profile-lifecycle.mjs +1289 -0
- package/lib/memorax-code-dsh-adapter/src/protocol.mjs +145 -0
- package/lib/memorax-code-dsh-adapter/src/runtime-state.mjs +132 -0
- package/lib/memorax-code-opencode-adapter/hooks/repo-memory-job.mjs +37 -0
- package/lib/memorax-code-opencode-adapter/package.json +10 -0
- package/lib/memorax-code-opencode-adapter/skills/memorax-code/SKILL.md +91 -0
- package/lib/memorax-code-opencode-adapter/skills/memorax-code/agents/claude.yaml +10 -0
- package/lib/memorax-code-opencode-adapter/skills/memorax-code/agents/openai.yaml +7 -0
- package/lib/memorax-code-opencode-adapter/skills/memorax-code/defaults.json +12 -0
- package/lib/memorax-code-opencode-adapter/skills/memorax-code/references/memorax-add.md +86 -0
- package/lib/memorax-code-opencode-adapter/skills/memorax-code/references/memorax-search.md +91 -0
- package/lib/memorax-code-opencode-adapter/skills/memorax-code/references/personal-read.md +46 -0
- package/lib/memorax-code-opencode-adapter/skills/memorax-code/references/personal-write.md +120 -0
- package/lib/memorax-code-opencode-adapter/skills/memorax-code/references/repo-build.md +319 -0
- package/lib/memorax-code-opencode-adapter/skills/memorax-code/references/repo-read.md +103 -0
- package/lib/memorax-code-opencode-adapter/skills/memorax-code/references/repo-templates.md +390 -0
- package/lib/memorax-code-opencode-adapter/skills/memorax-code/references/repo-update.md +127 -0
- package/lib/memorax-code-opencode-adapter/skills/memorax-code/scripts/collect_all.py +579 -0
- package/lib/memorax-code-opencode-adapter/skills/memorax-code/scripts/detect_updates.py +919 -0
- package/lib/memorax-code-opencode-adapter/skills/memorax-code/scripts/git_commit_facets.py +222 -0
- package/lib/memorax-code-opencode-adapter/skills/memorax-code/scripts/github_resource_facets.py +512 -0
- package/lib/memorax-code-opencode-adapter/skills/memorax-code/scripts/gitlab_resource_facets.py +517 -0
- package/lib/memorax-code-opencode-adapter/skills/memorax-code/scripts/prepare_repo_memory.py +411 -0
- package/lib/memorax-code-opencode-adapter/skills/memorax-code/scripts/user_profile_memory.py +528 -0
- package/lib/memorax-code-opencode-adapter/skills/memorax-code/scripts/validate_memory.py +248 -0
- package/lib/memorax-code-opencode-adapter/src/adapter-paths.mjs +37 -0
- package/lib/memorax-code-opencode-adapter/src/cli.mjs +260 -0
- package/lib/memorax-code-opencode-adapter/src/diagnostics.mjs +31 -0
- package/lib/memorax-code-opencode-adapter/src/plugin-install.mjs +673 -0
- package/lib/memorax-code-opencode-adapter/src/plugin.mjs +536 -0
- package/lib/memorax-code-opencode-adapter/src/repo-memory-server-runner.mjs +207 -0
- package/lib/resolve-claude-command.mjs +154 -1
- package/lib/resolve-codex-command.mjs +56 -1
- package/lib/run-entrypoint.mjs +6 -0
- package/package.json +7 -3
- package/lib/memorax-code-backend/dist/client-plugin-removal.js +0 -67
- /package/lib/memorax-code-backend/dist/{claude-transcript-turn.js → clients/claude/transcript-turn.js} +0 -0
- /package/lib/memorax-code-backend/dist/{codex-effective-prompt.js → clients/codex/effective-prompt.js} +0 -0
- /package/lib/memorax-code-backend/dist/{codex-rollout-turn.js → clients/codex/rollout-turn.js} +0 -0
- /package/lib/memorax-code-backend/dist/{codex-session-turn-index.js → clients/codex/session-turn-index.js} +0 -0
- /package/lib/memorax-code-backend/dist/{codex-workspace-links.js → clients/codex/workspace-links.js} +0 -0
- /package/lib/memorax-code-backend/dist/{backend-env.js → config/backend-env.js} +0 -0
- /package/lib/memorax-code-backend/dist/{proxy-env.js → config/proxy-env.js} +0 -0
- /package/lib/memorax-code-backend/dist/{entrypoint.js → entrypoints/main.js} +0 -0
- /package/lib/memorax-code-backend/dist/{backend-process.js → lifecycle/backend/process.js} +0 -0
- /package/lib/memorax-code-backend/dist/{backend-shutdown-request.js → lifecycle/backend/shutdown-request.js} +0 -0
- /package/lib/memorax-code-backend/dist/{backend-status.js → lifecycle/backend/status.js} +0 -0
- /package/lib/memorax-code-backend/dist/{adapter-lifecycle-participant.js → lifecycle/contracts.js} +0 -0
- /package/lib/memorax-code-backend/dist/{install-watchdog.js → lifecycle/install-watchdog.js} +0 -0
- /package/lib/memorax-code-backend/dist/{memory-observability.js → lifecycle/participant.js} +0 -0
- /package/lib/memorax-code-backend/dist/{memory-project.js → memory/project.js} +0 -0
- /package/lib/memorax-code-backend/dist/{incremental-jsonl-projection.js → shared/incremental-jsonl-projection.js} +0 -0
- /package/lib/memorax-code-backend/dist/{utils.js → shared/record.js} +0 -0
- /package/lib/memorax-code-backend/dist/{server-json.js → transport/http/json.js} +0 -0
- /package/lib/memorax-code-backend/dist/{memory-viewer-data-projection-cache.js → viewer/projection/cache.js} +0 -0
- /package/lib/memorax-code-backend/dist/{memory-viewer-event-identity.js → viewer/projection/event-identity.js} +0 -0
- /package/lib/memorax-code-backend/dist/{memory-viewer-redaction.js → viewer/projection/redaction.js} +0 -0
- /package/lib/memorax-code-backend/dist/{memory-viewer-turn-reference.js → viewer/projection/turn-reference.js} +0 -0
- /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
|
|
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",
|
|
75
|
+
repositoryKey: identityKey("workspace-directory", localWorkspace),
|
|
73
76
|
repositorySlug: workspaceName,
|
|
74
77
|
identitySource: "workspace-directory",
|
|
75
78
|
scopeKind: "local-directory",
|
|
76
|
-
|
|
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
|
|
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
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
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
|
|
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
|
|
206
|
-
return
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
422
|
+
throw new GitMetadataValidationError("invalid Git config value");
|
|
382
423
|
}
|
|
383
424
|
return result;
|
|
384
425
|
}
|
|
385
|
-
throw new
|
|
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
|
|
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
|
|
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
|
|
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 {
|
|
3
|
-
|
|
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("./
|
|
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 "./
|
|
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
|
|
@@ -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
|
+
}
|