fix(memory-plugin): setup wizard first-run path, proxy hint, config source reporting - #4387
Merged
t0saki merged 1 commit intoAug 27, 2026
Conversation
21 tasks
ZaynJarvis
approved these changes
Aug 27, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Fixes three defects in the shared memory-plugin code: the setup wizard cannot create a config on a fresh machine, the MCP proxy's connection-failure hint names a subcommand that does not exist, and the Claude Code plugin reports the wrong file as the source of the API key.
Defect 1 — the setup wizard cannot create a first-run config
Root cause.
runSetupWizardinexamples/memory-plugin-shared/lib/setup-wizard.mjsdestructuredcliPathfromloadCredentialFiles(env). Inexamples/memory-plugin-shared/lib/credentials.mjs,cliPathis deliberately""when the file does not exist (let cliPath = cliFile ? cliPathCandidate : ""), because callers use it as an "ovcli.conf is in play" signal; the path the user should write to is returned separately ascliPathCandidate. The wizard used the signal as if it were the path, so on a machine with no~/.openviking/ovcli.confit read, printed, and wrote the empty string.Introduced in.
f90556253—feat(plugins): stdio MCP proxy, remote marketplace install, and type-quota recall for memory plugins (#3039), which added bothsetup-wizard.mjsand thecliPath/cliPathCandidatesplit incredentials.mjsin the same commit. The wizard has never worked on a first run.Symptom.
node examples/claude-code-memory-plugin/scripts/setup.mjson a fresh machine printsConfig file:with a blank path and then either exits silently without writing anything or fails withENOENT: no such file or directory, open ''. This is the only supported configuration path for a pure-marketplace install with no installer script, so those users could not configure the plugin at all. Every harness that exposes the wizard is affected (Claude Code, Codex, opencode, pi).Fix. Fall back to
cliPathCandidatewhencliPathis empty, which keeps honoring an explicitOPENVIKING_CLI_CONFIG_FILEand otherwise resolves to~/.openviking/ovcli.conf. The existingmkdirSync(dirname(...), { recursive: true })before the write now runs against a real path, so a missing~/.openvikingdirectory is created.Verified. New
examples/memory-plugin-shared/setup-wizard.test.mjsdrives the wizard with scripted stdin; the first-run case fails withENOENT ... open ''against the pre-fix module and passes after. Also reproduced end to end:printf 'y\n\n\n\ny\n' | OPENVIKING_CLI_CONFIG_FILE=<tmp>/.openviking/ovcli.conf node examples/claude-code-memory-plugin/scripts/setup.mjsnow prints the real target path instead of a blank one.Defect 2 — the proxy error hint names a command that does not exist
Root cause. The JSON-RPC
-32001transport-failure path inexamples/memory-plugin-shared/lib/mcp-proxy-core.mjstold the user to check that'ov serve'is running. There is noov servesubcommand —ovis the Rust CLI, and the server is started withopenviking-server(see the entry points inpyproject.toml).Introduced in.
f90556253—feat(plugins): stdio MCP proxy, remote marketplace install, and type-quota recall for memory plugins (#3039), the commit that addedmcp-proxy-core.mjs.Symptom. Whenever the server is down or the URL is wrong, every harness's MCP tool call surfaces an error telling the user to run a command that does not exist;
ov serveexits with an unknown-subcommand error, sending the user down a dead end during exactly the failure they are trying to diagnose.Fix. The hint now reads
... and that the OpenViking server (\openviking-server`) is reachable.A repo-wide grep forov servenow returns nothing; all other occurrences were the generated copies of this same string, regenerated bysync.mjs`.Defect 3 —
loadConfig().configPathreports the wrong fileRoot cause.
examples/claude-code-memory-plugin/scripts/config.mjssetconfigPath: ovConf?.configPath || cliConf?.configPath, i.e. whichever config file merely parsed, withov.confunconditionally preferred. The actual credential chain is the opposite order and is per-field: env →ovcli.confapi_key→ov.confclaude_code.apiKey→ov.confserver.root_api_key.servers/mcp-proxy.mjsthen derivedcredentialSourcefromconfigPath.endsWith("ovcli.conf")and passedcredentialPath: cfg.configPath, so on any machine that has both files the proxy reportedov.confeven when the key came fromovcli.conf.scripts/ov-status.mjsre-implemented the real chain independently, so the two disagreed.Introduced in. The
configPathline dates to8c01e97ee—feat(cc-memory-plugin): persistent session and recall redesign (#1615), the commit that addedovcli.confas a credential source ahead ofov.confin the api_key chain while leavingconfigPathpreferringov.conf. It became user-visible inf90556253(#3039), which introducedservers/mcp-proxy.mjsand derivedcredentialSource/credentialPathfrom that field.Symptom. The proxy's debug
startlog line and thedata.credentialPathin its 401 error point at~/.openviking/ov.confwhile the key actually comes from~/.openviking/ovcli.conf— so an operator debugging a 401 edits the wrong file. On this machine, before the fix,loadConfig().configPathprinted theov.confpath whileov-status.mjsprintedapi_key from ~/.openviking/ovcli.conf. The Codex proxy had the same class of bug throughcredentialPath: creds.cliPath || creds.ovPath, which namesovcli.confwhenever that file exists even if the key came fromov.conf.Fix.
loadConfig()now also returnscredentialSource(env/ovcli/ov/none) andcredentialPath, computed by walking the same chain that producesapiKey— including the case whereapiKeyarrives throughovcli.conf'splugin.claude_codesection, which is reported asovcli.configPathkeeps its old meaning for backward compat.servers/mcp-proxy.mjsandscripts/ov-status.mjsboth read the new fields, so they can no longer disagree. On the shared side,resolveOpenVikingCredentialsgained the samecredentialPathand the Codex proxy now uses it.Verified. New
examples/claude-code-memory-plugin/scripts/config.test.mjscovers all five branches of the chain against throwaway config pairs;examples/codex-memory-plugin/scripts/ov-credentials.test.mjsgained a case for the shared resolver. Confirmed live on a machine with both files:loadConfig()now reportscredentialSource: ovcli/credentialPath: ~/.openviking/ovcli.conf, matchingov-status.mjs'sapi_key from ~/.openviking/ovcli.conf.Human Involvement
Related Issue
N/A
Type of Change
Changes Made
examples/memory-plugin-shared/lib/setup-wizard.mjs: write tocliPath || cliPathCandidateso a first run createsovcli.conf(and its parent directory) instead of writing to"".examples/memory-plugin-shared/lib/mcp-proxy-core.mjs: replace the nonexistent'ov serve'in the transport-failure hint withopenviking-server.examples/memory-plugin-shared/lib/credentials.mjs:resolveOpenVikingCredentialsnow returnscredentialPath, the file that actually supplied theapi_key(empty for env-sourced keys).examples/claude-code-memory-plugin/scripts/config.mjs:loadConfig()returnscredentialSourceandcredentialPathfollowing the real api_key chain;configPathis unchanged for backward compat.examples/claude-code-memory-plugin/servers/mcp-proxy.mjsandscripts/ov-status.mjs: consume the new fields so the proxy log, the proxy's 401 payload and/ovall name the same file.examples/codex-memory-plugin/servers/mcp-proxy.mjs: usecreds.credentialPathinstead ofcreds.cliPath || creds.ovPath.examples/memory-plugin-shared/setup-wizard.test.mjsandexamples/claude-code-memory-plugin/scripts/config.test.mjs, plus a new case inexamples/codex-memory-plugin/scripts/ov-credentials.test.mjs; both new files added to thenode --testlist in.github/workflows/pr.yml.sync.mjscopies of the three changed shared modules.Testing
node examples/memory-plugin-shared/sync.mjsfollowed by the workflow'snode --testlist: 221 tests, 221 passing.The wizard test was run against the pre-fix module to confirm it reproduces the defect (
Error: ENOENT: no such file or directory, open '') before passing against the fix.Two files in the workflow list,
install-agent-hooks.test.mjsandinstall-opencode-jsonc.test.mjs, fail when run from a linkedgit worktreerather than a normal checkout:install.sh'sresolve_self_checkouttests[ -d "$dir/../../.git" ], and in a worktree.gitis a file, soCHECKOUT_DIRstays empty and the marketplace directory resolves to/examples. This is unrelated to these changes and does not affect CI, which runs on a normal checkout.Checklist
Additional Notes
agent-plugins/servers/config.mjsandagent-plugins/servers/mcp-proxy.mjscarry the sameconfigPath/credentialSourcepattern as defect 3. It is left alone here to keep this change scoped to the plugins named above.