Skip to content

fix(cli): show the docs viewer the directories it could not read - #1131

Merged
7nohe merged 1 commit into
mainfrom
claude/optimistic-shirley-a36bae
Oct 1, 2026
Merged

7nohe merged 1 commit into
mainfrom
claude/optimistic-shirley-a36bae

Conversation

@7nohe

@7nohe 7nohe commented Oct 1, 2026

Copy link
Copy Markdown
Contributor

Summary

guren_get_plans (#1126) reports plan directories that would not list, but the docs viewer dropped them. The gap was larger than the viewer showing fewer plans. discoverPlanFiles walks the app root and docs/plans/**, and the docs scan (scanDocs → collectFiles) walks the same docs/plans and throws FileDiscoveryError there. So buildDocsViewerData rejected, /_guren/docs/data.json answered 500, and the page stayed empty or stale with no message, while the agent was told which directory failed.

  • buildDocsViewerData catches FileDiscoveryError from the docs graph only (anything else is rethrown) and carries it as docsScanFailure. Plans never read the docs graph, so they are still served. guren check --docs keeps reporting it as a failed discovery:read.
  • readViewerPlans(appRoot, discovery) takes the whole PlanDiscovery and returns unreadable beside open and hashes, including when no plan file was found. readPlanOverview() reuses it, so the viewer's unreadablePlanDirs and guren_get_plans' unreadable come from one composition.
  • relativeUnreadableDirs() in discovery.ts is the one way check --plan, the viewer and guren_get_plans name such a directory: app-relative, . for the app root, with the app root removed from the error's paths. Before this, guren_get_plans printed the absolute path in reason, and check --plan named the app root as an empty string.
  • The page lists the warnings above the open plans (scanWarnings() in the page model), and hides the "No documents found" hint when the scan stopped rather than found nothing.
  • web/scripts/prerender-docs-viewer.ts refuses to publish when either is set, since catching the failure would otherwise let a partial viewer through.

Not changed here: load() on the page still returns quietly on a non-OK response, and the server caches a rejected payload for its TTL. Other failures still go silent through those two paths.

Test plan

  • tests/docs-viewer-plans.test.ts: a synthetic discovery with no files and two unreadable directories; with docs/plans at mode 000 (skipped as root), readPlanOverview().unreadable equals the payload's unreadablePlanDirs, the root plan is still listed, and docsScanFailure names docs/plans. This case failed before the catch.
  • tests/docs-viewer-page.test.ts: scanWarnings() text.
  • tests/plan-check.test.ts: relativeUnreadableDirs(), including a sibling /tmp/app2 path left alone.
  • Checked in the browser against a temp app with docs/plans at 000: both warnings render above the plan list, and the readable plan and its entities are still drawn.
  • bun run build, bun run lint, tsc --noEmit, typecheck:build-configs, typecheck:scaffold-templates, the example and web typechecks, audit:prose, audit:docs, audit:core-first. The full test suite is left to CI.

A docs/plans directory that would not list made the docs scan throw,
so the viewer's data.json answered 500 and the page stayed empty or
stale with no message, while guren_get_plans named the directory.

buildDocsViewerData now catches that FileDiscoveryError (check --docs
still throws), carries it as docsScanFailure, and carries the plan
directories discoverPlanFiles could not list as unreadablePlanDirs.
readViewerPlans takes the whole discovery, so the viewer and
readPlanOverview share one composition, and relativeUnreadableDirs is
the one rule check --plan, the viewer and guren_get_plans name such a
directory by. The page lists both above the open plans.
@7nohe
7nohe merged commit a1f20e5 into main Oct 1, 2026
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant