Text (Markdown) lens + canvas polish + live-catalog validation + BFF - #8
Conversation
- Text lens: a data-driven Markdown card (title_column + text_column rendered via react-markdown; raw HTML off → XSS-safe; links open new-tab). Wired across core catalog + spec enums + web/Ink renderers; TUI shows raw source. - Canvas polish: fix the heavy drag-zoom (translate-only, not CSS.Transform's scaleX/scaleY) in the mixed-span grid; cap long card content with internal vertical scroll (max-h + overscroll-contain) so tall tiles don't dominate. - Client.queries() catalog listing (og.queries.list); validate resolves cell refs/params against the live catalog; catalog command surfaces server queries. - BFF: the browser holds no token for the same-origin /og proxy (readToken short-circuits proxy mode); the Node proxy owns auth injection. - Docs refresh (README / AGENTS / CLAUDE / canon). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Wrap the live-catalog fetch in its own try/catch so a network/server-down
failure reports `catalog_unreachable` ("catalog validation requires a reachable
server: …") rather than a generic `source` error — config/source errors stay
distinct. Cosmetic; behavior unchanged (still exits 1).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Text/Quote `text_column` is now required (z.string().min(1)) — a Text/Quote cell with rows but no text column was silently rendering the empty fallback instead of failing validation. (#3) - validate: warn when a *required* (non-nullable) catalog param is bound to $state without a default — it resolves at runtime, which validate can't see, so flag it rather than passing silently. (#2) - validate: document that the server-bound checks are intentional — structural parse already runs offline above; the meaningful ref/param validation needs a resolvable source by design. (#1, accepted-by-design) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
| if (isRecord(value) && "$state" in value) { | ||
| return "default" in value | ||
| ? { kind: "literal", value: value.default } | ||
| : { kind: "dynamic" }; |
There was a problem hiding this comment.
This classifier does not match the runtime resolver for $state params. A required catalog param like { $state: "/missing" } only produces a warning here, so validate can exit successfully even though runtime resolves the missing state path to undefined and invokes the server query without the required value. A malformed value like { $state: true, default: "fallback" } is also accepted as the literal default here, but runtime rejects the non-string $state before reading the default, so it sends undefined instead. The validator should reject malformed $state expressions and fail required dynamic params unless there is a value path that runtime will actually supply.
# Conflicts: # README.md
| } | ||
| } | ||
|
|
||
| for (const param of descriptors) { |
There was a problem hiding this comment.
This treats nullable catalog params as optional by skipping the missing-param error whenever param.nullable is true. If the catalog uses nullable to mean the parameter may be explicitly null, a notebook can omit that parameter entirely, validate exits successfully, and runtime later invokes the stored query without a value the server still expects. The missing check should distinguish optional params from params that only allow null as a value.
Post-merge work on the dash-books canvas (PR #7 → main is already merged; this stacks on top).
Component tier
title_column+text_column), rendering the first result row's prose. Web usesreact-markdown(raw HTML off → XSS-safe; links open in a new tab); the TUI degrades to the raw source. Distinct fromCard(labeled fields) andQuote(citation feed).Canvas polish
CSS.Translate(translate-only) instead ofCSS.Transform, which also applied dnd-kit'sscaleX/scaleYin our mixed-span grid.max-h-[28rem]) and scrolls inside the tile with contained overscroll; the card header stays fixed.Catalog + connection
Client.queries()— catalog listing overog.queries.list;validatenow resolves cellref/params against the live catalog, andcatalogsurfaces server queries./ogproxy; the Node proxy owns auth injection.Docs
Text, BFF/rawGq notes).Verified:
pnpm -r build && typecheck && testgreen (core/client/web/tui/cli). Demo notebook (~/exp/concept-graph, separate repo) exercises the Text card bound to/selected.🤖 Generated with Claude Code
Greptile Summary
This PR adds Markdown Text cards and tightens the server-backed notebook flow. The main changes are:
Textlens schemas and web/TUI renderers.validateand a newClient.queries()API./ogproxy token handling and Vite proxy header cleanup.Confidence Score: 4/5
This is close, but the catalog validation issue should be fixed before merging.
validatecan accept a notebook that omits a nullable catalog parameter.packages/cli/src/commands/validate.ts
Important Files Changed
queries()facade and reshapes catalog query metadata./ogproxy mode.Reviews (4): Last reviewed commit: "Merge remote-tracking branch 'origin/mai..." | Re-trigger Greptile
Context used: