Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions cli/serve.go
Original file line number Diff line number Diff line change
Expand Up @@ -690,6 +690,12 @@ func runServe(cmd *cobra.Command, args []string) error {
}
} else {
slog.Info("living-wiki globally disabled; dispatcher not started")
// TODO(option-D): consider defaulting enabled=true on fresh installs
// so the dispatcher starts automatically without requiring the operator
// to visit /settings/living-wiki first. Blocked on: (a) safety review
// (dispatcher calls out to LLMs which costs money / consumes local
// Ollama), (b) kill-switch semantics, (c) UX for the "auto-started but
// not configured" case. Filed as follow-up; do not implement here.
}
}

Expand Down
9 changes: 9 additions & 0 deletions docker-compose.hub.yml
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,15 @@ services:
- SOURCEBRIDGE_STORAGE_SURREAL_USER=${SURREAL_USER:-root}
- SOURCEBRIDGE_STORAGE_SURREAL_PASS=${SURREAL_PASS:-INSECURE-DEFAULT-CHANGE-ME-NOW}
- SOURCEBRIDGE_STORAGE_REDIS_MODE=memory
# Repo cache: /data is owned by the 'sourcebr' user (UID 1000) inside the
# API container. Without this, the default './repo-cache' resolves to
# /repo-cache (root-owned) and every addRepository call fails with
# "permission denied" before the git clone even starts.
# Note: /data/repo-cache lives inside the container filesystem and is NOT
# persisted across container restarts by default. The cache is fully
# rebuildable from git, so this is acceptable. If you want crash-safe
# caching, add a named volume mount for /data/repo-cache.
- SOURCEBRIDGE_STORAGE_REPO_CACHE_PATH=/data/repo-cache
- SOURCEBRIDGE_WORKER_ADDRESS=worker:50051
- SOURCEBRIDGE_SECURITY_GRPC_AUTH_SECRET=${SOURCEBRIDGE_GRPC_SECRET:-INSECURE-DEFAULT-CHANGE-ME-NOW}
- SOURCEBRIDGE_SECURITY_JWT_SECRET=${SOURCEBRIDGE_JWT_SECRET:-INSECURE-DEFAULT-CHANGE-ME-NOW}
Expand Down
9 changes: 9 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,15 @@ services:
- SOURCEBRIDGE_STORAGE_SURREAL_USER=root
- SOURCEBRIDGE_STORAGE_SURREAL_PASS=root
- SOURCEBRIDGE_STORAGE_REDIS_MODE=memory
# Repo cache: /data is owned by the 'sourcebr' user (UID 1000) inside the
# API container. Without this, the default './repo-cache' resolves to
# /repo-cache (root-owned) and every addRepository call fails with
# "permission denied" before the git clone even starts.
# Note: /data/repo-cache lives inside the container filesystem and is NOT
# persisted across container restarts by default. The cache is fully
# rebuildable from git, so this is acceptable. If you want crash-safe
# caching, add a named volume mount for /data/repo-cache.
- SOURCEBRIDGE_STORAGE_REPO_CACHE_PATH=/data/repo-cache
- SOURCEBRIDGE_WORKER_ADDRESS=worker:50051
- SOURCEBRIDGE_SECURITY_GRPC_AUTH_SECRET=${SOURCEBRIDGE_GRPC_SECRET:-dev-shared-secret}
- SOURCEBRIDGE_SECURITY_JWT_SECRET=${SOURCEBRIDGE_JWT_SECRET:-dev-jwt-secret-change-me}
Expand Down
32 changes: 32 additions & 0 deletions web/src/app/(app)/repositories/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { useMutation, useQuery } from "urql";
import {
ADD_REPOSITORY_MUTATION,
IMPORT_REQUIREMENTS_MUTATION as IMPORT_REQUIREMENTS,
LIVING_WIKI_GLOBAL_SETTINGS_QUERY,
REMOVE_REPOSITORY_MUTATION,
REPOSITORIES_LIGHT_QUERY as REPOSITORIES,
} from "@/lib/graphql/queries";
Expand Down Expand Up @@ -49,6 +50,7 @@ function statusTone(status: string) {
export default function RepositoriesPage() {
const router = useRouter();
const [result, reexecute] = useQuery({ query: REPOSITORIES });
const [lwResult] = useQuery({ query: LIVING_WIKI_GLOBAL_SETTINGS_QUERY });
const [, importReqs] = useMutation(IMPORT_REQUIREMENTS);
const [, addRepo] = useMutation(ADD_REPOSITORY_MUTATION);
const [, removeRepo] = useMutation(REMOVE_REPOSITORY_MUTATION);
Expand All @@ -71,6 +73,13 @@ export default function RepositoriesPage() {

const repos: Repository[] = result.data?.repositories || [];

// Show a banner when Living Wiki is globally disabled so the user knows
// they need to enable it in Settings before wiki features will work.
// null/undefined enabled counts as disabled (fresh install, no lw_settings row yet).
const lwSettings = lwResult.data?.livingWikiSettings;
const lwGlobalDisabled =
!lwResult.fetching && lwSettings != null && !lwSettings.enabled && !lwSettings.killSwitchActive;

const handleSSEEvent = useCallback(
(event: ServerEvent) => {
if (event.type === "repo.index.completed" || event.type === "repo.index.failed") {
Expand Down Expand Up @@ -212,6 +221,29 @@ export default function RepositoriesPage() {
}
/>

{lwGlobalDisabled && (
<div
role="status"
aria-live="polite"
className="flex items-start gap-3 rounded-[var(--radius-md)] border border-[var(--border-default)] bg-[var(--bg-surface)] px-4 py-3 text-sm"
>
<span className="mt-0.5 shrink-0 text-[var(--text-tertiary)]" aria-hidden="true">
</span>
<p className="text-[var(--text-secondary)]">
Living Wiki is globally disabled on this server. To start generating wiki
pages for your repositories, enable it in{" "}
<Link
href="/settings/living-wiki"
className="font-medium text-[var(--accent-primary)] hover:underline"
>
Settings → Living Wiki
</Link>
.
</p>
</div>
)}

{showAddForm ? (
<Panel variant="elevated" className="max-w-3xl space-y-5">
<div className="space-y-1">
Expand Down
Loading