mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-24 19:35:28 -06:00
docs: document doctor configuration checks
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
/** Doctor note for workspace bootstrap file size and truncation risk. */
|
||||
import { note } from "../../packages/terminal-core/src/note.js";
|
||||
import { resolveAgentWorkspaceDir, resolveDefaultAgentId } from "../agents/agent-scope.js";
|
||||
import {
|
||||
@@ -30,6 +31,11 @@ function formatCauses(causes: Array<"per-file-limit" | "total-limit">): string {
|
||||
return causes.map((cause) => (cause === "per-file-limit" ? "max/file" : "max/total")).join(", ");
|
||||
}
|
||||
|
||||
/**
|
||||
* Analyzes configured bootstrap files and emits warnings when injection will truncate content.
|
||||
*
|
||||
* Returns the raw budget analysis for tests and callers that need structured evidence.
|
||||
*/
|
||||
export async function noteBootstrapFileSize(cfg: OpenClawConfig) {
|
||||
const workspaceDir = resolveAgentWorkspaceDir(cfg, resolveDefaultAgentId(cfg));
|
||||
const bootstrapMaxChars = resolveBootstrapMaxChars(cfg);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/** Facade-backed doctor checks and cleanup for bundled browser plugin state. */
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import { note } from "../../packages/terminal-core/src/note.js";
|
||||
@@ -27,6 +28,7 @@ export type BrowserDoctorRepairDeps = {
|
||||
movePathToTrash?: (targetPath: string) => Promise<string>;
|
||||
};
|
||||
|
||||
/** Legacy browser profile paths detected before cleanup moves them aside. */
|
||||
export type LegacyClawdBrowserProfileResidue = {
|
||||
legacyProfileDir: string;
|
||||
legacyUserDataDir: string;
|
||||
@@ -64,6 +66,7 @@ function mayHaveLegacyClawdBrowserProfileResidue(deps?: BrowserDoctorRepairDeps)
|
||||
}
|
||||
}
|
||||
|
||||
/** Emits browser readiness notes through the bundled browser plugin doctor surface. */
|
||||
export async function noteChromeMcpBrowserReadiness(cfg: OpenClawConfig, deps?: BrowserDoctorDeps) {
|
||||
try {
|
||||
await loadBrowserDoctorSurface().noteChromeMcpBrowserReadiness(cfg, deps);
|
||||
@@ -74,6 +77,7 @@ export async function noteChromeMcpBrowserReadiness(cfg: OpenClawConfig, deps?:
|
||||
}
|
||||
}
|
||||
|
||||
/** Detects old clawd browser profile residue without loading plugin cleanup when paths are absent. */
|
||||
export async function detectLegacyClawdBrowserProfileResidue(
|
||||
cfg: OpenClawConfig,
|
||||
deps?: BrowserDoctorRepairDeps,
|
||||
@@ -88,6 +92,7 @@ export async function detectLegacyClawdBrowserProfileResidue(
|
||||
return detect(cfg, deps);
|
||||
}
|
||||
|
||||
/** Archives legacy clawd browser profile residue through the browser plugin repair hook. */
|
||||
export async function maybeArchiveLegacyClawdBrowserProfileResidue(
|
||||
cfg: OpenClawConfig,
|
||||
deps?: BrowserDoctorRepairDeps,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/** Doctor health note for Claude CLI binary, auth, and workspace/project directories. */
|
||||
import fs from "node:fs";
|
||||
import {
|
||||
normalizeOptionalLowercaseString,
|
||||
@@ -191,6 +192,12 @@ function resolveClaudeCliWorkspaceTargets(params: {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Emits Claude CLI health diagnostics for every agent currently routed through the CLI backend.
|
||||
*
|
||||
* The optional deps let tests inject auth stores, PATH resolution, and workspace roots without
|
||||
* touching the user's real Claude credentials or filesystem.
|
||||
*/
|
||||
export function noteClaudeCliHealth(
|
||||
cfg: OpenClawConfig,
|
||||
deps?: {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/** Doctor warning for missing command owners on privileged channel commands. */
|
||||
import { normalizeOptionalString } from "@openclaw/normalization-core/string-coerce";
|
||||
import { normalizeStringEntries } from "@openclaw/normalization-core/string-normalization";
|
||||
import { note } from "../../packages/terminal-core/src/note.js";
|
||||
@@ -13,10 +14,12 @@ function resolveConfiguredCommandOwners(cfg: OpenClawConfig): string[] {
|
||||
return normalizeStringEntries(owners.map((entry) => String(entry ?? "")));
|
||||
}
|
||||
|
||||
/** Returns true when at least one owner sender id is configured. */
|
||||
export function hasConfiguredCommandOwners(cfg: OpenClawConfig): boolean {
|
||||
return resolveConfiguredCommandOwners(cfg).length > 0;
|
||||
}
|
||||
|
||||
/** Formats a channel sender id into the commands.ownerAllowFrom entry shape. */
|
||||
export function formatCommandOwnerFromChannelSender(params: {
|
||||
channel: PairingChannel;
|
||||
id: string;
|
||||
@@ -35,6 +38,7 @@ export function formatCommandOwnerFromChannelSender(params: {
|
||||
return `${params.channel}:${id}`;
|
||||
}
|
||||
|
||||
/** Emits setup guidance when privileged command ownership is not configured. */
|
||||
export function noteCommandOwnerHealth(cfg: OpenClawConfig): void {
|
||||
if (hasConfiguredCommandOwners(cfg)) {
|
||||
return;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/** Doctor checks and repair effects for cached shell completion setup. */
|
||||
import { spawnSync } from "node:child_process";
|
||||
import path from "node:path";
|
||||
import { note } from "../../packages/terminal-core/src/note.js";
|
||||
@@ -86,6 +87,7 @@ export async function checkShellCompletionStatus(
|
||||
};
|
||||
}
|
||||
|
||||
/** Converts shell completion status into health findings shown by check flows. */
|
||||
export function shellCompletionStatusToHealthFindings(
|
||||
status: ShellCompletionStatus,
|
||||
): readonly HealthFinding[] {
|
||||
@@ -116,6 +118,7 @@ export function shellCompletionStatusToHealthFindings(
|
||||
return [];
|
||||
}
|
||||
|
||||
/** Converts shell completion status into dry-run repair effects for health check reporting. */
|
||||
export function shellCompletionStatusToRepairEffects(
|
||||
status: ShellCompletionStatus,
|
||||
): readonly HealthRepairEffect[] {
|
||||
@@ -151,10 +154,10 @@ export type DoctorCompletionOptions = {
|
||||
};
|
||||
|
||||
/**
|
||||
* Doctor check for shell completion.
|
||||
* - If profile uses slow dynamic pattern: upgrade to cached version
|
||||
* - If profile has completion but no cache: auto-generate cache and upgrade profile
|
||||
* - If no completion at all: prompt to install (with user confirmation)
|
||||
* Repairs shell completion setup when doctor runs interactively.
|
||||
*
|
||||
* Slow dynamic profiles are upgraded to cached completion; configured profiles with a missing
|
||||
* cache regenerate it; missing completion prompts unless non-interactive mode is active.
|
||||
*/
|
||||
export async function doctorShellCompletion(
|
||||
_runtime: RuntimeEnv,
|
||||
@@ -164,14 +167,13 @@ export async function doctorShellCompletion(
|
||||
const cliName = resolveCliName();
|
||||
const status = await checkShellCompletionStatus(cliName);
|
||||
|
||||
// Profile uses slow dynamic pattern - upgrade to cached version
|
||||
// Slow dynamic completion runs the CLI during shell startup; cache it to keep login shells fast.
|
||||
if (status.usesSlowPattern) {
|
||||
note(
|
||||
`Your ${status.shell} profile uses slow dynamic completion (source <(...)).\nUpgrading to cached completion for faster shell startup...`,
|
||||
"Shell completion",
|
||||
);
|
||||
|
||||
// Ensure cache exists first
|
||||
if (!status.cacheExists) {
|
||||
const generated = await generateCompletionCache();
|
||||
if (!generated) {
|
||||
@@ -183,13 +185,11 @@ export async function doctorShellCompletion(
|
||||
}
|
||||
}
|
||||
|
||||
// Upgrade profile to use cached file
|
||||
await installCompletion(status.shell, true, cliName);
|
||||
note(formatCompletionReloadNote(status.shell, "upgraded"), "Shell completion");
|
||||
return;
|
||||
}
|
||||
|
||||
// Profile has completion but no cache - auto-fix
|
||||
if (status.profileInstalled && !status.cacheExists) {
|
||||
note(
|
||||
`Shell completion is configured in your ${status.shell} profile but the cache is missing.\nRegenerating cache...`,
|
||||
@@ -207,10 +207,8 @@ export async function doctorShellCompletion(
|
||||
return;
|
||||
}
|
||||
|
||||
// No completion at all - prompt to install
|
||||
if (!status.profileInstalled) {
|
||||
if (options.nonInteractive) {
|
||||
// In non-interactive mode, just note that completion is not installed
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -220,7 +218,6 @@ export async function doctorShellCompletion(
|
||||
});
|
||||
|
||||
if (shouldInstall) {
|
||||
// First generate the cache
|
||||
const generated = await generateCompletionCache();
|
||||
if (!generated) {
|
||||
note(
|
||||
@@ -230,18 +227,13 @@ export async function doctorShellCompletion(
|
||||
return;
|
||||
}
|
||||
|
||||
// Then install to profile
|
||||
await installCompletion(status.shell, true, cliName);
|
||||
note(formatCompletionReloadNote(status.shell, "installed"), "Shell completion");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure completion cache exists. Used during setup/update to fix
|
||||
* cases where profile has completion but no cache.
|
||||
* This is a silent fix - no prompts.
|
||||
*/
|
||||
/** Ensures the shell completion cache exists without prompting during setup/update flows. */
|
||||
export async function ensureCompletionCacheExists(binName = "openclaw"): Promise<boolean> {
|
||||
const shell = resolveShellFromEnv() as CompletionShell;
|
||||
const cacheExists = await completionCacheExists(shell, binName);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/** Doctor analysis helpers for config schema cleanup and ambiguous model fallback shapes. */
|
||||
import path from "node:path";
|
||||
import { resolvePrimaryStringValue } from "@openclaw/normalization-core/string-coerce";
|
||||
import type { ZodIssue } from "zod";
|
||||
@@ -21,6 +22,7 @@ function isUnrecognizedKeysIssue(issue: ZodIssue): issue is UnrecognizedKeysIssu
|
||||
return issue.code === "unrecognized_keys";
|
||||
}
|
||||
|
||||
/** Formats a parsed config issue path into a user-facing dotted path. */
|
||||
export function formatConfigPath(parts: Array<string | number>): string {
|
||||
if (parts.length === 0) {
|
||||
return "<root>";
|
||||
@@ -36,6 +38,7 @@ export function formatConfigPath(parts: Array<string | number>): string {
|
||||
return out || "<root>";
|
||||
}
|
||||
|
||||
/** Resolves a config path against a loose config tree, returning null for invalid traversal. */
|
||||
export function resolveConfigPathTarget(root: unknown, pathLocal: Array<string | number>): unknown {
|
||||
let current: unknown = root;
|
||||
for (const part of pathLocal) {
|
||||
@@ -71,6 +74,12 @@ const STRIP_PROTECTED_KEYS: Record<string, Set<string>> = {
|
||||
plugins: new Set(["installs"]),
|
||||
};
|
||||
|
||||
/**
|
||||
* Removes unknown config keys reported by schema validation, except protected migration keys.
|
||||
*
|
||||
* Doctor skips this while an update is in progress so partially written upgrade state is not
|
||||
* stripped before its migration can finish.
|
||||
*/
|
||||
export function stripUnknownConfigKeys(config: OpenClawConfig): {
|
||||
config: OpenClawConfig;
|
||||
removed: string[];
|
||||
@@ -119,6 +128,7 @@ export function stripUnknownConfigKeys(config: OpenClawConfig): {
|
||||
return { config: next, removed };
|
||||
}
|
||||
|
||||
/** Warns when legacy OpenCode provider overrides shadow the built-in catalog. */
|
||||
export function noteOpencodeProviderOverrides(cfg: OpenClawConfig): void {
|
||||
const providers = cfg.models?.providers;
|
||||
if (!providers) {
|
||||
@@ -174,6 +184,7 @@ function isImplicitFallbackClobber(model: unknown): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Collects warnings for agent model shapes that unintentionally drop default fallbacks. */
|
||||
export function collectImplicitFallbackClobberWarnings(cfg: OpenClawConfig): string[] {
|
||||
const defaultFallbacks = resolveAgentModelFallbackValues(cfg.agents?.defaults?.model);
|
||||
if (defaultFallbacks.length === 0) {
|
||||
@@ -204,6 +215,7 @@ export function collectImplicitFallbackClobberWarnings(cfg: OpenClawConfig): str
|
||||
return warnings;
|
||||
}
|
||||
|
||||
/** Emits doctor notes for model fallback clobber warnings. */
|
||||
export function noteImplicitFallbackClobberWarnings(cfg: OpenClawConfig): void {
|
||||
const warnings = collectImplicitFallbackClobberWarnings(cfg);
|
||||
if (warnings.length === 0) {
|
||||
@@ -212,6 +224,7 @@ export function noteImplicitFallbackClobberWarnings(cfg: OpenClawConfig): void {
|
||||
note(warnings.join("\n"), "Doctor warnings");
|
||||
}
|
||||
|
||||
/** Emits a config include warning when an include path escapes the config directory. */
|
||||
export function noteIncludeConfinementWarning(snapshot: {
|
||||
path?: string | null;
|
||||
issues?: Array<{ message: string }>;
|
||||
|
||||
Reference in New Issue
Block a user