A merged PR may require knowledge-base updates. Review the change and update library/ as needed.
Source PR
- PR: #297 - fix: route shadowing, registry dedupe, cursor login probe, pollinate ack honesty
- Author: @thenotoriousllama
- Merged into:
main
- Files changed: 20
PR description
What this does
Four small, independent quick-win fixes, one commit each:
1. Route shadowing — ISS-012
GET /api/memories/conflicts, /stale-refs, and /history returned 404 because mountMemoriesApi registered the parametric GET /:id before mountLifecycleApi registered those literal routes — Hono matches in registration order, so /:id captured id === "conflicts" etc. Applied the same remedy as the earlier /prime route-shadow fix: extracted registerLifecycleReadRoutes (src/daemon/runtime/memories/lifecycle-api.ts) and call it inside mountMemoriesApi immediately before GET /:id; mountLifecycleApi remains as the standalone back-compat shim (never-reached duplicates under production wiring). New SP-7 route-order regression suite asserts all three literals answer non-404 while /:id still resolves.
2. Duplicate project registry rows — ISS-021
Binding a project could double every registry row: the bind handler's upsert and the sync-heal re-upsert both run the non-transactional SELECT→INSERT in updateOrInsertByKey, and the sync triggered by the bind's own cache invalidation reads an eventually-consistent registry that can miss the bind's INSERT. Both layers implemented in src/daemon/runtime/projects/registry-sync.ts: (a) backstop dedupe — the registry read collapses through a Map keyed by project_id (first row wins) and the merged list is deduped the same way, so a doubled row can never reach the cache or the API; (b) root mitigation — the sync-heal skips local-only projects that carry a local folder binding (the bind path owns their registry write); unbound legacy entries still heal.
3. cursor-agent login probe stub — ISS-017
probeCursorLogin (src/cli/health-probes.ts) returned ok:false "login state unknown" on both branches and never ran cursor-agent. It now runs cursor-agent status via spawnSync with shell: true (cursor-agent is a .cmd shim on Windows; Node >= 22 throws EINVAL without shell ��
Files touched
.claude-plugin/marketplace.json (+2/-2)
.claude-plugin/plugin.json (+1/-1)
CHANGELOG.md (+4/-0)
harnesses/claude-code/.claude-plugin/plugin.json (+1/-1)
harnesses/codex/package.json (+1/-1)
harnesses/openclaw/openclaw.plugin.json (+1/-1)
harnesses/openclaw/package.json (+1/-1)
package-lock.json (+2/-2)
package.json (+1/-1)
src/cli/health-probes.ts (+63/-9)
src/commands/pollinate.ts (+19/-5)
src/daemon/runtime/assemble.ts (+4/-0)
src/daemon/runtime/memories/api.ts (+13/-0)
src/daemon/runtime/memories/lifecycle-api.ts (+32/-15)
src/daemon/runtime/pollinating/api.ts (+69/-26)
src/daemon/runtime/projects/registry-sync.ts (+41/-4)
tests/cli/health-probes.test.ts (+69/-1)
tests/daemon/runtime/memories/lifecycle-route-order.test.ts (+142/-0)
tests/daemon/runtime/pollinating/api.test.ts (+65/-5)
tests/daemon/runtime/projects/registry-sync.test.ts (+100/-0)
Auto-generated by .github/workflows/kb-issue-on-merge.yaml on merge.
A merged PR may require knowledge-base updates. Review the change and update
library/as needed.Source PR
mainPR description
What this does
Four small, independent quick-win fixes, one commit each:
1. Route shadowing — ISS-012
GET /api/memories/conflicts,/stale-refs, and/historyreturned 404 becausemountMemoriesApiregistered the parametricGET /:idbeforemountLifecycleApiregistered those literal routes — Hono matches in registration order, so/:idcapturedid === "conflicts"etc. Applied the same remedy as the earlier/primeroute-shadow fix: extractedregisterLifecycleReadRoutes(src/daemon/runtime/memories/lifecycle-api.ts) and call it insidemountMemoriesApiimmediately beforeGET /:id;mountLifecycleApiremains as the standalone back-compat shim (never-reached duplicates under production wiring). New SP-7 route-order regression suite asserts all three literals answer non-404 while/:idstill resolves.2. Duplicate project registry rows — ISS-021
Binding a project could double every registry row: the bind handler's upsert and the sync-heal re-upsert both run the non-transactional SELECT→INSERT in
updateOrInsertByKey, and the sync triggered by the bind's own cache invalidation reads an eventually-consistent registry that can miss the bind's INSERT. Both layers implemented in src/daemon/runtime/projects/registry-sync.ts: (a) backstop dedupe — the registry read collapses through a Map keyed byproject_id(first row wins) and the merged list is deduped the same way, so a doubled row can never reach the cache or the API; (b) root mitigation — the sync-heal skips local-only projects that carry a local folder binding (the bind path owns their registry write); unbound legacy entries still heal.3. cursor-agent login probe stub — ISS-017
probeCursorLogin(src/cli/health-probes.ts) returned ok:false "login state unknown" on both branches and never ran cursor-agent. It now runscursor-agent statusviaspawnSyncwithshell: true(cursor-agent is a.cmdshim on Windows; Node >= 22 throws EINVAL without shell ��Files touched
.claude-plugin/marketplace.json(+2/-2).claude-plugin/plugin.json(+1/-1)CHANGELOG.md(+4/-0)harnesses/claude-code/.claude-plugin/plugin.json(+1/-1)harnesses/codex/package.json(+1/-1)harnesses/openclaw/openclaw.plugin.json(+1/-1)harnesses/openclaw/package.json(+1/-1)package-lock.json(+2/-2)package.json(+1/-1)src/cli/health-probes.ts(+63/-9)src/commands/pollinate.ts(+19/-5)src/daemon/runtime/assemble.ts(+4/-0)src/daemon/runtime/memories/api.ts(+13/-0)src/daemon/runtime/memories/lifecycle-api.ts(+32/-15)src/daemon/runtime/pollinating/api.ts(+69/-26)src/daemon/runtime/projects/registry-sync.ts(+41/-4)tests/cli/health-probes.test.ts(+69/-1)tests/daemon/runtime/memories/lifecycle-route-order.test.ts(+142/-0)tests/daemon/runtime/pollinating/api.test.ts(+65/-5)tests/daemon/runtime/projects/registry-sync.test.ts(+100/-0)Auto-generated by
.github/workflows/kb-issue-on-merge.yamlon merge.