feat(wiki): [[wikilinks]] with redlinks + cross-project resolver (Issue B)

Last P2 from Antoine's "daily-usable" sprint. Entities referenced via
[[Name]] in descriptions or mirror markdown now render as:

- live wikilink if the name matches an entity in the same project
- live cross-project link with "(in project X)" scope indicator if the
  only match is in another project
- red italic redlink pointing at /wiki/new?name=... otherwise

Clicking a redlink opens a pre-filled "create this entity" form that
POSTs to /v1/entities and redirects to the new entity's page.

- engineering/wiki.py: _wikilink_transform + _resolve_wikilink,
  applied in render_project (pre-markdown) and render_entity
  (description body). render_new_entity_form for the create page.
  CSS for .wikilink / .wikilink-cross / .redlink / .new-entity-form
- api/routes.py: GET /wiki/new?name&project
- tests/test_wikilinks.py: 12 tests including the spec regression
  (A references [[B]] -> redlink; create B -> link becomes live)
- DEV-LEDGER.md: session log + test_count 521 -> 533

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-22 09:15:14 -04:00
parent b94f9dff56
commit e147ab2abd
4 changed files with 298 additions and 2 deletions

View File

@@ -129,6 +129,13 @@ def wiki_capture() -> HTMLResponse:
return HTMLResponse(content=render_capture())
@router.get("/wiki/new", response_class=HTMLResponse)
def wiki_new_entity(name: str = "", project: str = "") -> HTMLResponse:
"""Issue B: "create this entity" form pre-filled from a redlink."""
from atocore.engineering.wiki import render_new_entity_form
return HTMLResponse(content=render_new_entity_form(name=name, project=project))
@router.get("/wiki/memories/{memory_id}", response_class=HTMLResponse)
def wiki_memory(memory_id: str) -> HTMLResponse:
"""Phase 7E: memory detail with audit trail + neighbors."""