Tags: hypn4/lumen
Tags
fix(plugin)!: invoke lumen via node launcher in all manifests
Phase 2 of the run.cmd polyglot elimination plan. Migrates every host's
mcpServers / hooks command from \`scripts/run.cmd\` (the polyglot whose
byte-0 conflict cycled through three regressions) to
\`node \${PLUGIN_ROOT}/launcher.mjs\`. After this commit no live code
path reaches \`scripts/run.cmd\`; the polyglot remains in the tree as
dead code through the soak window before Phase 3 deletes it.
BREAKING CHANGE: the MCP server command and hook commands now invoke
\`node\` instead of a shell-mediated launcher script. End users on
Claude Code, Cursor, OpenCode, and Codex must have Node 18+ on their
spawn PATH. Most users already do (Claude Code, Cursor, OpenCode all
ship Node; Codex's official MCP examples assume \`npx\`). Codex users
on a pure Homebrew install with no Node should follow the updated
.codex/INSTALL.md troubleshooting note.
Per-host changes:
- .claude-plugin/plugin.json: command → \${user_config.node_command}
(default \"node\"), args → [\${PLUGIN_ROOT}/launcher.mjs, stdio]. New
userConfig.node_command lets users with PATH issues set an absolute
path without editing the manifest.
- hooks/hooks.json: SessionStart now runs prefetch THEN session-start,
warming the cache before the MCP server's first invocation. Both
hook commands use \${user_config.node_command}.
- .cursor/mcp.json + hooks/hooks-cursor.json: command → \"node\", args
→ launcher.mjs path. Cursor's manifest doesn't support
\${user_config.*} substitution; document absolute-path workaround
inline if needed.
- .opencode/plugins/lumen.js: spawn target swapped to
[process.execPath, launcher, ...]. New prefetch() runs synchronously
before config.mcp.lumen registration with a 90 s hard timeout cap so
a wedged launcher can't hang opencode startup. OpenCode's MCP
startup window (5 s documented, 15-30 s observed) is too tight for
cold-cache fetches; pre-warming during config-load bypasses it.
- .codex/INSTALL.md: register with \`--startup-timeout-sec 60\` (Codex
default 10 s is borderline tight). Documents Node 18+ prerequisite,
PATH-visibility troubleshooting (codex#6243 absolute-path
workaround), config.toml persistence, manual prefetch warm-up, and
cache directory location for clean uninstalls.
- README.md, .opencode/INSTALL.md, .cursor-plugin/INSTALL.md: install
snippets updated to launcher.mjs invocation.
What this PR does NOT do:
- Phase 3 (delete scripts/run.{cmd,sh,bat} + their tests) — waits for
the soak window (two tagged releases or 14 days).
- ory/lumen upstream submission — this PR targets the fork (hypn4/lumen)
for CI verification first.
Closes the structural cause of ory#152 and the regression class
documented in docs/run-cmd-polyglot-root-fix-proposal.md and the
obra/superpowers history (anthropics/claude-plugins-official#1692).
test(integration): tolerate Windows file-lock on hook test cleanup
Phase 1 CI showed Integration (windows-latest) failing with:
testing.go:1464: TempDir RemoveAll cleanup: unlinkat
...lumen\debug.log: The process cannot access the file because
it is being used by another process.
Root cause: SessionStart hook spawns a detached background indexer
(cmd/hook_spawn_windows.go) that opens debug.log and index.db. On
Windows, files cannot be unlinked while a process holds an open
handle, so t.TempDir()'s strict cleanup reports an error and marks
the test FAIL even though the test logic itself succeeded — the JSON
output was generated, hook exit was clean, and the launcher chain
worked correctly. Linux/macOS allow unlink-while-open so the same
test passes there.
Fix: replace t.TempDir() with sandboxTempDir() — a helper that uses
os.MkdirTemp() and a t.Cleanup that downgrades RemoveAll errors to
t.Logf instead of t.Errorf. Test-only change; production code (the
background indexer behavior) is intentionally unchanged.
Verification: TestLauncherSpawnStdioHandshake, the actual polyglot
regression gate, already PASSED on windows-latest in the previous
run. This commit only fixes the cleanup noise that was masquerading
as a test failure on the SessionStart hook tests.