-
Notifications
You must be signed in to change notification settings - Fork 94
fix(docs): async install docs generation + home-repo guard #314
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,105 @@ | ||
| /** | ||
| * The docs-onboarding step of `hivemind install`, factored out of | ||
| * `runInstallAll` so it can be tested deterministically (no pty, no network). | ||
| * | ||
| * Behaviour, all decided here: | ||
| * - Resolve the git root; if we can't prompt (no TTY / not signed in / not a | ||
| * repo) OR the root is the user's $HOME, fall back to the one-time hint. | ||
| * - Otherwise: build the graph INLINE (fast, no LLM), run the onboarding | ||
| * (generate? → agent? → auto?), and on consent spawn `docs wiki` DETACHED | ||
| * so the LLM generation never blocks install — mirroring `graph init`. | ||
| * - A docs hiccup must never break install: the effectful section is guarded | ||
| * and returns "noop" on failure. | ||
| * | ||
| * Everything effectful is injected, so a test asserts the exact decision + | ||
| * the exact worker spawn without touching git, the graph, or the backend. | ||
| */ | ||
|
|
||
| import { isHomeRoot, shouldPromptDocsSetup } from "./install-hint.js"; | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
| import type { OnboardingResult } from "./onboarding.js"; | ||
|
|
||
| export interface InstallDocsDeps { | ||
| cwd: string; | ||
| interactive: boolean; | ||
| loggedIn: boolean; | ||
| home: string; | ||
| /** git toplevel for cwd, or null when not a repo. May throw → treated as null. */ | ||
| gitTopLevel: (cwd: string) => string | null; | ||
| /** Org config, or null when unavailable. */ | ||
| loadCfg: () => { orgId: string; orgName?: string } | null; | ||
| /** Is auto docs-sync already enabled for (org, repo)? Then don't re-prompt. */ | ||
| autoEnabled: (orgId: string, root: string) => boolean; | ||
| /** Build the code graph inline (fast, no LLM). */ | ||
| buildGraph: (root: string) => Promise<void>; | ||
| /** Run the interactive consent flow. */ | ||
| onboard: (a: { root: string; orgId: string; orgName?: string }) => Promise<OnboardingResult>; | ||
| /** Spawn a detached CLI worker (e.g. ["docs","wiki","--cwd",root]). False = no CLI entry. */ | ||
| spawn: (args: string[]) => boolean; | ||
| /** Print the one-time informational hint (sentinel-gated by the caller). */ | ||
| showHint: () => void; | ||
| log: (m: string) => void; | ||
| warn: (m: string) => void; | ||
| } | ||
|
|
||
| export type InstallDocsAction = | ||
| | { kind: "hint" } // couldn't/needn't prompt → hint shown | ||
| | { kind: "already-enabled"; root: string } // auto already on → no re-prompt | ||
| | { kind: "declined" } // prompted, user said no to generate | ||
| | { kind: "spawned"; root: string } // consented → wiki spawned DETACHED | ||
| | { kind: "no-entry"; root: string } // consented but no CLI entry to spawn | ||
| | { kind: "noop" }; // no cfg, or a guarded failure | ||
|
|
||
| export async function runInstallDocsOnboarding(d: InstallDocsDeps): Promise<InstallDocsAction> { | ||
| let inGitRepo = false; | ||
| let repoRoot = d.cwd; | ||
| try { | ||
| const top = d.gitTopLevel(d.cwd); | ||
| inGitRepo = top !== null; | ||
| repoRoot = top ?? d.cwd; | ||
| } catch { | ||
| /* probe unavailable → treat as not-a-repo, fall through to the hint */ | ||
| } | ||
|
|
||
| const prompt = shouldPromptDocsSetup({ | ||
| interactive: d.interactive, | ||
| inGitRepo, | ||
| loggedIn: d.loggedIn, | ||
| atHome: isHomeRoot(repoRoot, d.home), | ||
| }); | ||
| if (!prompt) { | ||
| d.showHint(); | ||
| return { kind: "hint" }; | ||
| } | ||
|
|
||
| try { | ||
| const cfg = d.loadCfg(); | ||
| if (!cfg) return { kind: "noop" }; | ||
| // Already set up: don't re-ASK (nothing new to consent to). Still build the | ||
| // graph — its post-build auto-refresh regenerates in the background, so an | ||
| // auto-enabled-but-empty corpus still gets filled (idempotent when full). | ||
| if (d.autoEnabled(cfg.orgId, repoRoot)) { | ||
| d.log(""); | ||
| await d.buildGraph(repoRoot); | ||
| d.log("Docs auto-sync is on for this repo — refreshing in the background. See: hivemind docs list"); | ||
| return { kind: "already-enabled", root: repoRoot }; | ||
| } | ||
| d.log(""); | ||
| d.log("Docs (optional): set up documentation for this repository."); | ||
| await d.buildGraph(repoRoot); | ||
| const result = await d.onboard({ root: repoRoot, orgId: cfg.orgId, orgName: cfg.orgName }); | ||
| if (!result.generate) return { kind: "declined" }; | ||
| // Only the wiki here — same as `hivemind graph init`. Per-file docs are a | ||
| // separate, heavy `docs generate` (every file × LLM); auto-sync generates | ||
| // them later on commit. `docs refresh` would NOT create missing per-file | ||
| // docs (it only refreshes drifted existing rows), so spawning it is a no-op. | ||
| if (d.spawn(["docs", "wiki", "--cwd", repoRoot])) { | ||
| d.log("Generating wiki docs in the background — check with: hivemind docs list"); | ||
| return { kind: "spawned", root: repoRoot }; | ||
| } | ||
| d.log("Run `hivemind docs wiki` to generate the corpus."); | ||
| return { kind: "no-entry", root: repoRoot }; | ||
| } catch (err) { | ||
| d.warn(`docs setup skipped: ${err instanceof Error ? err.message : String(err)}`); | ||
| return { kind: "noop" }; | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.