fix: prefer ~ for home paths in output

This commit is contained in:
Peter Steinberger
2026-01-23 03:43:32 +00:00
parent 34bb7250f8
commit 7f68bf79b6
44 changed files with 245 additions and 152 deletions

View File

@@ -12,7 +12,7 @@ import { CONFIG_PATH_CLAWDBOT, writeConfigFile } from "../config/config.js";
import { DEFAULT_AGENT_ID, normalizeAgentId } from "../routing/session-key.js";
import type { RuntimeEnv } from "../runtime.js";
import { defaultRuntime } from "../runtime.js";
import { resolveUserPath } from "../utils.js";
import { resolveUserPath, shortenHomePath } from "../utils.js";
import { createClackPrompter } from "../wizard/clack-prompter.js";
import { WizardCancelledError } from "../wizard/prompts.js";
import {
@@ -126,7 +126,7 @@ export async function agentsAddCommand(
: { config: nextConfig, added: [], skipped: [], conflicts: [] };
await writeConfigFile(bindingResult.config);
if (!opts.json) runtime.log(`Updated ${CONFIG_PATH_CLAWDBOT}`);
if (!opts.json) runtime.log(`Updated ${shortenHomePath(CONFIG_PATH_CLAWDBOT)}`);
const quietRuntime = opts.json ? createQuietRuntime(runtime) : runtime;
await ensureWorkspaceAndSessions(workspaceDir, quietRuntime, {
skipBootstrap: Boolean(bindingResult.config.agents?.defaults?.skipBootstrap),
@@ -151,8 +151,8 @@ export async function agentsAddCommand(
runtime.log(JSON.stringify(payload, null, 2));
} else {
runtime.log(`Agent: ${agentId}`);
runtime.log(`Workspace: ${workspaceDir}`);
runtime.log(`Agent dir: ${agentDir}`);
runtime.log(`Workspace: ${shortenHomePath(workspaceDir)}`);
runtime.log(`Agent dir: ${shortenHomePath(agentDir)}`);
if (model) runtime.log(`Model: ${model}`);
if (bindingResult.conflicts.length > 0) {
runtime.error(
@@ -334,7 +334,7 @@ export async function agentsAddCommand(
}
await writeConfigFile(nextConfig);
runtime.log(`Updated ${CONFIG_PATH_CLAWDBOT}`);
runtime.log(`Updated ${shortenHomePath(CONFIG_PATH_CLAWDBOT)}`);
await ensureWorkspaceAndSessions(workspaceDir, runtime, {
skipBootstrap: Boolean(nextConfig.agents?.defaults?.skipBootstrap),
agentId,

View File

@@ -4,6 +4,7 @@ import { resolveSessionTranscriptsDirForAgent } from "../config/sessions.js";
import { DEFAULT_AGENT_ID, normalizeAgentId } from "../routing/session-key.js";
import type { RuntimeEnv } from "../runtime.js";
import { defaultRuntime } from "../runtime.js";
import { shortenHomePath } from "../utils.js";
import { createClackPrompter } from "../wizard/clack-prompter.js";
import { createQuietRuntime, requireValidConfig } from "./agents.command-shared.js";
@@ -69,7 +70,7 @@ export async function agentsDeleteCommand(
const result = pruneAgentConfig(cfg, agentId);
await writeConfigFile(result.config);
if (!opts.json) runtime.log(`Updated ${CONFIG_PATH_CLAWDBOT}`);
if (!opts.json) runtime.log(`Updated ${shortenHomePath(CONFIG_PATH_CLAWDBOT)}`);
const quietRuntime = opts.json ? createQuietRuntime(runtime) : runtime;
await moveToTrash(workspaceDir, quietRuntime);

View File

@@ -9,7 +9,7 @@ import type { IdentityConfig } from "../config/types.js";
import { normalizeAgentId } from "../routing/session-key.js";
import type { RuntimeEnv } from "../runtime.js";
import { defaultRuntime } from "../runtime.js";
import { resolveUserPath } from "../utils.js";
import { resolveUserPath, shortenHomePath } from "../utils.js";
import { requireValidConfig } from "./agents.command-shared.js";
import {
type AgentIdentity,
@@ -105,14 +105,14 @@ export async function agentsSetIdentityCommand(
const matches = resolveAgentIdByWorkspace(cfg, workspaceDir);
if (matches.length === 0) {
runtime.error(
`No agent workspace matches ${workspaceDir}. Pass --agent to target a specific agent.`,
`No agent workspace matches ${shortenHomePath(workspaceDir)}. Pass --agent to target a specific agent.`,
);
runtime.exit(1);
return;
}
if (matches.length > 1) {
runtime.error(
`Multiple agents match ${workspaceDir}: ${matches.join(", ")}. Pass --agent to choose one.`,
`Multiple agents match ${shortenHomePath(workspaceDir)}: ${matches.join(", ")}. Pass --agent to choose one.`,
);
runtime.exit(1);
return;
@@ -131,7 +131,7 @@ export async function agentsSetIdentityCommand(
const targetPath =
identityFilePath ??
(workspaceDir ? path.join(workspaceDir, DEFAULT_IDENTITY_FILENAME) : "IDENTITY.md");
runtime.error(`No identity data found in ${targetPath}.`);
runtime.error(`No identity data found in ${shortenHomePath(targetPath)}.`);
runtime.exit(1);
return;
}
@@ -211,11 +211,11 @@ export async function agentsSetIdentityCommand(
return;
}
runtime.log(`Updated ${CONFIG_PATH_CLAWDBOT}`);
runtime.log(`Updated ${shortenHomePath(CONFIG_PATH_CLAWDBOT)}`);
runtime.log(`Agent: ${agentId}`);
if (nextIdentity.name) runtime.log(`Name: ${nextIdentity.name}`);
if (nextIdentity.theme) runtime.log(`Theme: ${nextIdentity.theme}`);
if (nextIdentity.emoji) runtime.log(`Emoji: ${nextIdentity.emoji}`);
if (nextIdentity.avatar) runtime.log(`Avatar: ${nextIdentity.avatar}`);
if (workspaceDir) runtime.log(`Workspace: ${workspaceDir}`);
if (workspaceDir) runtime.log(`Workspace: ${shortenHomePath(workspaceDir)}`);
}

View File

@@ -3,6 +3,7 @@ import { normalizeAgentId } from "../routing/session-key.js";
import type { RuntimeEnv } from "../runtime.js";
import { defaultRuntime } from "../runtime.js";
import { formatCliCommand } from "../cli/command-format.js";
import { shortenHomePath } from "../utils.js";
import { describeBinding } from "./agents.bindings.js";
import { requireValidConfig } from "./agents.command-shared.js";
import type { AgentSummary } from "./agents.config.js";
@@ -40,8 +41,8 @@ function formatSummary(summary: AgentSummary) {
if (identityLine) {
lines.push(` Identity: ${identityLine}${identitySource ? ` (${identitySource})` : ""}`);
}
lines.push(` Workspace: ${summary.workspace}`);
lines.push(` Agent dir: ${summary.agentDir}`);
lines.push(` Workspace: ${shortenHomePath(summary.workspace)}`);
lines.push(` Agent dir: ${shortenHomePath(summary.agentDir)}`);
if (summary.model) lines.push(` Model: ${summary.model}`);
lines.push(` Routing rules: ${summary.bindings}`);

View File

@@ -4,7 +4,7 @@ import path from "node:path";
import { resolveDefaultAgentWorkspaceDir } from "../agents/workspace.js";
import type { ClawdbotConfig } from "../config/config.js";
import type { RuntimeEnv } from "../runtime.js";
import { resolveHomeDir, resolveUserPath } from "../utils.js";
import { resolveHomeDir, resolveUserPath, shortenHomeInString } from "../utils.js";
export type RemovalResult = {
ok: boolean;
@@ -53,20 +53,21 @@ export async function removePath(
if (!target?.trim()) return { ok: false, skipped: true };
const resolved = path.resolve(target);
const label = opts?.label ?? resolved;
const displayLabel = shortenHomeInString(label);
if (isUnsafeRemovalTarget(resolved)) {
runtime.error(`Refusing to remove unsafe path: ${label}`);
runtime.error(`Refusing to remove unsafe path: ${displayLabel}`);
return { ok: false };
}
if (opts?.dryRun) {
runtime.log(`[dry-run] remove ${label}`);
runtime.log(`[dry-run] remove ${displayLabel}`);
return { ok: true, skipped: true };
}
try {
await fs.rm(resolved, { recursive: true, force: true });
runtime.log(`Removed ${label}`);
runtime.log(`Removed ${displayLabel}`);
return { ok: true };
} catch (err) {
runtime.error(`Failed to remove ${label}: ${String(err)}`);
runtime.error(`Failed to remove ${displayLabel}: ${String(err)}`);
return { ok: false };
}
}

View File

@@ -4,6 +4,7 @@ import type { ClawdbotConfig } from "../config/config.js";
import { CONFIG_PATH_CLAWDBOT } from "../config/config.js";
import type { RuntimeEnv } from "../runtime.js";
import { note } from "../terminal/note.js";
import { shortenHomePath } from "../utils.js";
import { confirm, select } from "./configure.shared.js";
import { guardCancel } from "./onboard-helpers.js";
@@ -51,7 +52,7 @@ export async function removeChannelConfigWizard(
const label = getChannelPlugin(channel)?.meta.label ?? channel;
const confirmed = guardCancel(
await confirm({
message: `Delete ${label} configuration from ${CONFIG_PATH_CLAWDBOT}?`,
message: `Delete ${label} configuration from ${shortenHomePath(CONFIG_PATH_CLAWDBOT)}?`,
initialValue: false,
}),
runtime,

View File

@@ -10,7 +10,7 @@ import { ensureControlUiAssetsBuilt } from "../infra/control-ui-assets.js";
import type { RuntimeEnv } from "../runtime.js";
import { defaultRuntime } from "../runtime.js";
import { note } from "../terminal/note.js";
import { resolveUserPath } from "../utils.js";
import { resolveUserPath, shortenHomePath } from "../utils.js";
import { createClackPrompter } from "../wizard/clack-prompter.js";
import { WizardCancelledError } from "../wizard/prompts.js";
import { removeChannelConfigWizard } from "./configure.channels.js";
@@ -253,7 +253,7 @@ export async function runConfigureWizard(
mode,
});
await writeConfigFile(remoteConfig);
runtime.log(`Updated ${CONFIG_PATH_CLAWDBOT}`);
runtime.log(`Updated ${shortenHomePath(CONFIG_PATH_CLAWDBOT)}`);
outro("Remote gateway configured.");
return;
}
@@ -286,7 +286,7 @@ export async function runConfigureWizard(
mode,
});
await writeConfigFile(nextConfig);
runtime.log(`Updated ${CONFIG_PATH_CLAWDBOT}`);
runtime.log(`Updated ${shortenHomePath(CONFIG_PATH_CLAWDBOT)}`);
};
if (opts.sections) {

View File

@@ -6,6 +6,7 @@ import { promisify } from "node:util";
import type { ClawdbotConfig } from "../config/config.js";
import { note } from "../terminal/note.js";
import { shortenHomePath } from "../utils.js";
const execFileAsync = promisify(execFile);
@@ -19,10 +20,11 @@ export async function noteMacLaunchAgentOverrides() {
const hasMarker = fs.existsSync(markerPath);
if (!hasMarker) return;
const displayMarkerPath = shortenHomePath(markerPath);
const lines = [
`- LaunchAgent writes are disabled via ${markerPath}.`,
`- LaunchAgent writes are disabled via ${displayMarkerPath}.`,
"- To restore default behavior:",
` rm ${markerPath}`,
` rm ${displayMarkerPath}`,
].filter((line): line is string => Boolean(line));
note(lines.join("\n"), "Gateway (macOS)");
}

View File

@@ -13,6 +13,7 @@ import {
resolveStorePath,
} from "../config/sessions.js";
import { note } from "../terminal/note.js";
import { shortenHomePath } from "../utils.js";
type DoctorPrompterLike = {
confirmSkipInNonInteractive: (params: {
@@ -131,11 +132,16 @@ export async function noteStateIntegrity(
const sessionsDir = resolveSessionTranscriptsDirForAgent(agentId, env, homedir);
const storePath = resolveStorePath(cfg.session?.store, { agentId });
const storeDir = path.dirname(storePath);
const displayStateDir = shortenHomePath(stateDir);
const displayOauthDir = shortenHomePath(oauthDir);
const displaySessionsDir = shortenHomePath(sessionsDir);
const displayStoreDir = shortenHomePath(storeDir);
const displayConfigPath = configPath ? shortenHomePath(configPath) : undefined;
let stateDirExists = existsDir(stateDir);
if (!stateDirExists) {
warnings.push(
`- CRITICAL: state directory missing (${stateDir}). Sessions, credentials, logs, and config are stored there.`,
`- CRITICAL: state directory missing (${displayStateDir}). Sessions, credentials, logs, and config are stored there.`,
);
if (cfg.gateway?.mode === "remote") {
warnings.push(
@@ -143,26 +149,26 @@ export async function noteStateIntegrity(
);
}
const create = await prompter.confirmSkipInNonInteractive({
message: `Create ${stateDir} now?`,
message: `Create ${displayStateDir} now?`,
initialValue: false,
});
if (create) {
const created = ensureDir(stateDir);
if (created.ok) {
changes.push(`- Created ${stateDir}`);
changes.push(`- Created ${displayStateDir}`);
stateDirExists = true;
} else {
warnings.push(`- Failed to create ${stateDir}: ${created.error}`);
warnings.push(`- Failed to create ${displayStateDir}: ${created.error}`);
}
}
}
if (stateDirExists && !canWriteDir(stateDir)) {
warnings.push(`- State directory not writable (${stateDir}).`);
warnings.push(`- State directory not writable (${displayStateDir}).`);
const hint = dirPermissionHint(stateDir);
if (hint) warnings.push(` ${hint}`);
const repair = await prompter.confirmSkipInNonInteractive({
message: `Repair permissions on ${stateDir}?`,
message: `Repair permissions on ${displayStateDir}?`,
initialValue: true,
});
if (repair) {
@@ -170,9 +176,9 @@ export async function noteStateIntegrity(
const stat = fs.statSync(stateDir);
const target = addUserRwx(stat.mode);
fs.chmodSync(stateDir, target);
changes.push(`- Repaired permissions on ${stateDir}`);
changes.push(`- Repaired permissions on ${displayStateDir}`);
} catch (err) {
warnings.push(`- Failed to repair ${stateDir}: ${String(err)}`);
warnings.push(`- Failed to repair ${displayStateDir}: ${String(err)}`);
}
}
}
@@ -181,19 +187,19 @@ export async function noteStateIntegrity(
const stat = fs.statSync(stateDir);
if ((stat.mode & 0o077) !== 0) {
warnings.push(
`- State directory permissions are too open (${stateDir}). Recommend chmod 700.`,
`- State directory permissions are too open (${displayStateDir}). Recommend chmod 700.`,
);
const tighten = await prompter.confirmSkipInNonInteractive({
message: `Tighten permissions on ${stateDir} to 700?`,
message: `Tighten permissions on ${displayStateDir} to 700?`,
initialValue: true,
});
if (tighten) {
fs.chmodSync(stateDir, 0o700);
changes.push(`- Tightened permissions on ${stateDir} to 700`);
changes.push(`- Tightened permissions on ${displayStateDir} to 700`);
}
}
} catch (err) {
warnings.push(`- Failed to read ${stateDir} permissions: ${String(err)}`);
warnings.push(`- Failed to read ${displayStateDir} permissions: ${String(err)}`);
}
}
@@ -202,19 +208,21 @@ export async function noteStateIntegrity(
const stat = fs.statSync(configPath);
if ((stat.mode & 0o077) !== 0) {
warnings.push(
`- Config file is group/world readable (${configPath}). Recommend chmod 600.`,
`- Config file is group/world readable (${displayConfigPath ?? configPath}). Recommend chmod 600.`,
);
const tighten = await prompter.confirmSkipInNonInteractive({
message: `Tighten permissions on ${configPath} to 600?`,
message: `Tighten permissions on ${displayConfigPath ?? configPath} to 600?`,
initialValue: true,
});
if (tighten) {
fs.chmodSync(configPath, 0o600);
changes.push(`- Tightened permissions on ${configPath} to 600`);
changes.push(`- Tightened permissions on ${displayConfigPath ?? configPath} to 600`);
}
}
} catch (err) {
warnings.push(`- Failed to read config permissions (${configPath}): ${String(err)}`);
warnings.push(
`- Failed to read config permissions (${displayConfigPath ?? configPath}): ${String(err)}`,
);
}
}
@@ -223,26 +231,33 @@ export async function noteStateIntegrity(
dirCandidates.set(sessionsDir, "Sessions dir");
dirCandidates.set(storeDir, "Session store dir");
dirCandidates.set(oauthDir, "OAuth dir");
const displayDirFor = (dir: string) => {
if (dir === sessionsDir) return displaySessionsDir;
if (dir === storeDir) return displayStoreDir;
if (dir === oauthDir) return displayOauthDir;
return shortenHomePath(dir);
};
for (const [dir, label] of dirCandidates) {
const displayDir = displayDirFor(dir);
if (!existsDir(dir)) {
warnings.push(`- CRITICAL: ${label} missing (${dir}).`);
warnings.push(`- CRITICAL: ${label} missing (${displayDir}).`);
const create = await prompter.confirmSkipInNonInteractive({
message: `Create ${label} at ${dir}?`,
message: `Create ${label} at ${displayDir}?`,
initialValue: true,
});
if (create) {
const created = ensureDir(dir);
if (created.ok) {
changes.push(`- Created ${label}: ${dir}`);
changes.push(`- Created ${label}: ${displayDir}`);
} else {
warnings.push(`- Failed to create ${dir}: ${created.error}`);
warnings.push(`- Failed to create ${displayDir}: ${created.error}`);
}
}
continue;
}
if (!canWriteDir(dir)) {
warnings.push(`- ${label} not writable (${dir}).`);
warnings.push(`- ${label} not writable (${displayDir}).`);
const hint = dirPermissionHint(dir);
if (hint) warnings.push(` ${hint}`);
const repair = await prompter.confirmSkipInNonInteractive({
@@ -254,9 +269,9 @@ export async function noteStateIntegrity(
const stat = fs.statSync(dir);
const target = addUserRwx(stat.mode);
fs.chmodSync(dir, target);
changes.push(`- Repaired permissions on ${label}: ${dir}`);
changes.push(`- Repaired permissions on ${label}: ${displayDir}`);
} catch (err) {
warnings.push(`- Failed to repair ${dir}: ${String(err)}`);
warnings.push(`- Failed to repair ${displayDir}: ${String(err)}`);
}
}
}
@@ -274,8 +289,8 @@ export async function noteStateIntegrity(
warnings.push(
[
"- Multiple state directories detected. This can split session history.",
...Array.from(extraStateDirs).map((dir) => ` - ${dir}`),
` Active state dir: ${stateDir}`,
...Array.from(extraStateDirs).map((dir) => ` - ${shortenHomePath(dir)}`),
` Active state dir: ${displayStateDir}`,
].join("\n"),
);
}
@@ -311,7 +326,7 @@ export async function noteStateIntegrity(
const transcriptPath = resolveSessionFilePath(mainEntry.sessionId, mainEntry, { agentId });
if (!existsFile(transcriptPath)) {
warnings.push(
`- Main session transcript missing (${transcriptPath}). History will appear to reset.`,
`- Main session transcript missing (${shortenHomePath(transcriptPath)}). History will appear to reset.`,
);
} else {
const lineCount = countJsonlLines(transcriptPath);

View File

@@ -8,6 +8,7 @@ import {
DEFAULT_SOUL_FILENAME,
DEFAULT_USER_FILENAME,
} from "../agents/workspace.js";
import { shortenHomePath } from "../utils.js";
export const MEMORY_SYSTEM_PROMPT = [
"Memory system not found in workspace.",
@@ -80,8 +81,8 @@ export function detectLegacyWorkspaceDirs(params: {
export function formatLegacyWorkspaceWarning(detection: LegacyWorkspaceDetection): string {
return [
"Extra workspace directories detected (may contain old agent files):",
...detection.legacyDirs.map((dir) => `- ${dir}`),
`Active workspace: ${detection.activeWorkspace}`,
...detection.legacyDirs.map((dir) => `- ${shortenHomePath(dir)}`),
`Active workspace: ${shortenHomePath(detection.activeWorkspace)}`,
"If unused, archive or move to Trash (e.g. trash ~/clawdbot).",
].join("\n");
}

View File

@@ -20,6 +20,7 @@ import type { RuntimeEnv } from "../runtime.js";
import { defaultRuntime } from "../runtime.js";
import { note } from "../terminal/note.js";
import { stylePromptTitle } from "../terminal/prompt-style.js";
import { shortenHomePath } from "../utils.js";
import { maybeRepairAnthropicOAuthProfileId, noteAuthProfileHealth } from "./doctor-auth.js";
import { loadAndMaybeMigrateDoctorConfig } from "./doctor-config-flow.js";
import { maybeRepairGatewayDaemon } from "./doctor-gateway-daemon-flow.js";
@@ -269,10 +270,10 @@ export async function doctorCommand(
if (shouldWriteConfig) {
cfg = applyWizardMetadata(cfg, { command: "doctor", mode: resolveMode(cfg) });
await writeConfigFile(cfg);
runtime.log(`Updated ${CONFIG_PATH_CLAWDBOT}`);
runtime.log(`Updated ${shortenHomePath(CONFIG_PATH_CLAWDBOT)}`);
const backupPath = `${CONFIG_PATH_CLAWDBOT}.bak`;
if (fs.existsSync(backupPath)) {
runtime.log(`Backup: ${backupPath}`);
runtime.log(`Backup: ${shortenHomePath(backupPath)}`);
}
} else {
runtime.log(`Run "${formatCliCommand("clawdbot doctor --fix")}" to apply changes.`);

View File

@@ -1,5 +1,6 @@
import { CONFIG_PATH_CLAWDBOT, loadConfig } from "../../config/config.js";
import type { RuntimeEnv } from "../../runtime.js";
import { shortenHomePath } from "../../utils.js";
import {
ensureFlagCompatibility,
normalizeAlias,
@@ -74,7 +75,7 @@ export async function modelsAliasesAddCommand(
};
});
runtime.log(`Updated ${CONFIG_PATH_CLAWDBOT}`);
runtime.log(`Updated ${shortenHomePath(CONFIG_PATH_CLAWDBOT)}`);
runtime.log(`Alias ${alias} -> ${resolved.provider}/${resolved.model}`);
}
@@ -105,7 +106,7 @@ export async function modelsAliasesRemoveCommand(aliasRaw: string, runtime: Runt
};
});
runtime.log(`Updated ${CONFIG_PATH_CLAWDBOT}`);
runtime.log(`Updated ${shortenHomePath(CONFIG_PATH_CLAWDBOT)}`);
if (
!updated.agents?.defaults?.models ||
Object.values(updated.agents.defaults.models).every((entry) => !entry?.alias?.trim())

View File

@@ -23,6 +23,7 @@ import {
} from "../../config/config.js";
import type { RuntimeEnv } from "../../runtime.js";
import { stylePromptHint, stylePromptMessage } from "../../terminal/prompt-style.js";
import { shortenHomePath } from "../../utils.js";
import { applyAuthProfileConfig } from "../onboard-auth.js";
import { isRemoteEnvironment } from "../oauth-env.js";
import { openUrl } from "../onboard-helpers.js";
@@ -117,7 +118,7 @@ export async function modelsAuthSetupTokenCommand(
}),
);
runtime.log(`Updated ${CONFIG_PATH_CLAWDBOT}`);
runtime.log(`Updated ${shortenHomePath(CONFIG_PATH_CLAWDBOT)}`);
runtime.log(`Auth profile: ${CLAUDE_CLI_PROFILE_ID} (anthropic/oauth)`);
}
@@ -159,7 +160,7 @@ export async function modelsAuthPasteTokenCommand(
await updateConfig((cfg) => applyAuthProfileConfig(cfg, { profileId, provider, mode: "token" }));
runtime.log(`Updated ${CONFIG_PATH_CLAWDBOT}`);
runtime.log(`Updated ${shortenHomePath(CONFIG_PATH_CLAWDBOT)}`);
runtime.log(`Auth profile: ${profileId} (${provider}/token)`);
}
@@ -425,7 +426,7 @@ export async function modelsAuthLoginCommand(opts: LoginOptions, runtime: Runtim
return next;
});
runtime.log(`Updated ${CONFIG_PATH_CLAWDBOT}`);
runtime.log(`Updated ${shortenHomePath(CONFIG_PATH_CLAWDBOT)}`);
for (const profile of result.profiles) {
runtime.log(
`Auth profile: ${profile.profileId} (${profile.credential.provider}/${credentialMode(profile.credential)})`,

View File

@@ -1,6 +1,7 @@
import { buildModelAliasIndex, resolveModelRefFromString } from "../../agents/model-selection.js";
import { CONFIG_PATH_CLAWDBOT, loadConfig } from "../../config/config.js";
import type { RuntimeEnv } from "../../runtime.js";
import { shortenHomePath } from "../../utils.js";
import {
DEFAULT_PROVIDER,
ensureFlagCompatibility,
@@ -78,7 +79,7 @@ export async function modelsFallbacksAddCommand(modelRaw: string, runtime: Runti
};
});
runtime.log(`Updated ${CONFIG_PATH_CLAWDBOT}`);
runtime.log(`Updated ${shortenHomePath(CONFIG_PATH_CLAWDBOT)}`);
runtime.log(`Fallbacks: ${(updated.agents?.defaults?.model?.fallbacks ?? []).join(", ")}`);
}
@@ -124,7 +125,7 @@ export async function modelsFallbacksRemoveCommand(modelRaw: string, runtime: Ru
};
});
runtime.log(`Updated ${CONFIG_PATH_CLAWDBOT}`);
runtime.log(`Updated ${shortenHomePath(CONFIG_PATH_CLAWDBOT)}`);
runtime.log(`Fallbacks: ${(updated.agents?.defaults?.model?.fallbacks ?? []).join(", ")}`);
}
@@ -148,6 +149,6 @@ export async function modelsFallbacksClearCommand(runtime: RuntimeEnv) {
};
});
runtime.log(`Updated ${CONFIG_PATH_CLAWDBOT}`);
runtime.log(`Updated ${shortenHomePath(CONFIG_PATH_CLAWDBOT)}`);
runtime.log("Fallback list cleared.");
}

View File

@@ -1,6 +1,7 @@
import { buildModelAliasIndex, resolveModelRefFromString } from "../../agents/model-selection.js";
import { CONFIG_PATH_CLAWDBOT, loadConfig } from "../../config/config.js";
import type { RuntimeEnv } from "../../runtime.js";
import { shortenHomePath } from "../../utils.js";
import {
DEFAULT_PROVIDER,
ensureFlagCompatibility,
@@ -78,7 +79,7 @@ export async function modelsImageFallbacksAddCommand(modelRaw: string, runtime:
};
});
runtime.log(`Updated ${CONFIG_PATH_CLAWDBOT}`);
runtime.log(`Updated ${shortenHomePath(CONFIG_PATH_CLAWDBOT)}`);
runtime.log(
`Image fallbacks: ${(updated.agents?.defaults?.imageModel?.fallbacks ?? []).join(", ")}`,
);
@@ -126,7 +127,7 @@ export async function modelsImageFallbacksRemoveCommand(modelRaw: string, runtim
};
});
runtime.log(`Updated ${CONFIG_PATH_CLAWDBOT}`);
runtime.log(`Updated ${shortenHomePath(CONFIG_PATH_CLAWDBOT)}`);
runtime.log(
`Image fallbacks: ${(updated.agents?.defaults?.imageModel?.fallbacks ?? []).join(", ")}`,
);
@@ -152,6 +153,6 @@ export async function modelsImageFallbacksClearCommand(runtime: RuntimeEnv) {
};
});
runtime.log(`Updated ${CONFIG_PATH_CLAWDBOT}`);
runtime.log(`Updated ${shortenHomePath(CONFIG_PATH_CLAWDBOT)}`);
runtime.log("Image fallback list cleared.");
}

View File

@@ -250,7 +250,7 @@ export async function modelsStatusCommand(
rawModel && rawModel !== resolvedLabel ? `${resolvedLabel} (from ${rawModel})` : resolvedLabel;
runtime.log(
`${label("Config")}${colorize(rich, theme.muted, ":")} ${colorize(rich, theme.info, CONFIG_PATH_CLAWDBOT)}`,
`${label("Config")}${colorize(rich, theme.muted, ":")} ${colorize(rich, theme.info, shortenHomePath(CONFIG_PATH_CLAWDBOT))}`,
);
runtime.log(
`${label("Agent dir")}${colorize(rich, theme.muted, ":")} ${colorize(

View File

@@ -4,6 +4,7 @@ import { type ModelScanResult, scanOpenRouterModels } from "../../agents/model-s
import { withProgressTotals } from "../../cli/progress.js";
import { CONFIG_PATH_CLAWDBOT, loadConfig } from "../../config/config.js";
import type { RuntimeEnv } from "../../runtime.js";
import { shortenHomePath } from "../../utils.js";
import {
stylePromptHint,
stylePromptMessage,
@@ -343,7 +344,7 @@ export async function modelsScanCommand(
return;
}
runtime.log(`Updated ${CONFIG_PATH_CLAWDBOT}`);
runtime.log(`Updated ${shortenHomePath(CONFIG_PATH_CLAWDBOT)}`);
runtime.log(`Fallbacks: ${selected.join(", ")}`);
if (selectedImages.length > 0) {
runtime.log(`Image fallbacks: ${selectedImages.join(", ")}`);

View File

@@ -1,6 +1,7 @@
import { CONFIG_PATH_CLAWDBOT } from "../../config/config.js";
import type { RuntimeEnv } from "../../runtime.js";
import { resolveModelTarget, updateConfig } from "./shared.js";
import { shortenHomePath } from "../../utils.js";
export async function modelsSetImageCommand(modelRaw: string, runtime: RuntimeEnv) {
const updated = await updateConfig((cfg) => {
@@ -27,6 +28,6 @@ export async function modelsSetImageCommand(modelRaw: string, runtime: RuntimeEn
};
});
runtime.log(`Updated ${CONFIG_PATH_CLAWDBOT}`);
runtime.log(`Updated ${shortenHomePath(CONFIG_PATH_CLAWDBOT)}`);
runtime.log(`Image model: ${updated.agents?.defaults?.imageModel?.primary ?? modelRaw}`);
}

View File

@@ -1,6 +1,7 @@
import { CONFIG_PATH_CLAWDBOT } from "../../config/config.js";
import type { RuntimeEnv } from "../../runtime.js";
import { resolveModelTarget, updateConfig } from "./shared.js";
import { shortenHomePath } from "../../utils.js";
export async function modelsSetCommand(modelRaw: string, runtime: RuntimeEnv) {
const updated = await updateConfig((cfg) => {
@@ -27,6 +28,6 @@ export async function modelsSetCommand(modelRaw: string, runtime: RuntimeEnv) {
};
});
runtime.log(`Updated ${CONFIG_PATH_CLAWDBOT}`);
runtime.log(`Updated ${shortenHomePath(CONFIG_PATH_CLAWDBOT)}`);
runtime.log(`Default model: ${updated.agents?.defaults?.model?.primary ?? modelRaw}`);
}

View File

@@ -18,7 +18,13 @@ import { runCommandWithTimeout } from "../process/exec.js";
import type { RuntimeEnv } from "../runtime.js";
import { stylePromptTitle } from "../terminal/prompt-style.js";
import { GATEWAY_CLIENT_MODES, GATEWAY_CLIENT_NAMES } from "../utils/message-channel.js";
import { CONFIG_DIR, resolveUserPath, sleep } from "../utils.js";
import {
CONFIG_DIR,
resolveUserPath,
shortenHomeInString,
shortenHomePath,
sleep,
} from "../utils.js";
import { VERSION } from "../version.js";
import type { NodeManagerChoice, OnboardMode, ResetScope } from "./onboard-types.js";
@@ -33,21 +39,21 @@ export function guardCancel<T>(value: T | symbol, runtime: RuntimeEnv): T {
export function summarizeExistingConfig(config: ClawdbotConfig): string {
const rows: string[] = [];
const defaults = config.agents?.defaults;
if (defaults?.workspace) rows.push(`workspace: ${defaults.workspace}`);
if (defaults?.workspace) rows.push(shortenHomeInString(`workspace: ${defaults.workspace}`));
if (defaults?.model) {
const model = typeof defaults.model === "string" ? defaults.model : defaults.model.primary;
if (model) rows.push(`model: ${model}`);
if (model) rows.push(shortenHomeInString(`model: ${model}`));
}
if (config.gateway?.mode) rows.push(`gateway.mode: ${config.gateway.mode}`);
if (config.gateway?.mode) rows.push(shortenHomeInString(`gateway.mode: ${config.gateway.mode}`));
if (typeof config.gateway?.port === "number") {
rows.push(`gateway.port: ${config.gateway.port}`);
rows.push(shortenHomeInString(`gateway.port: ${config.gateway.port}`));
}
if (config.gateway?.bind) rows.push(`gateway.bind: ${config.gateway.bind}`);
if (config.gateway?.bind) rows.push(shortenHomeInString(`gateway.bind: ${config.gateway.bind}`));
if (config.gateway?.remote?.url) {
rows.push(`gateway.remote.url: ${config.gateway.remote.url}`);
rows.push(shortenHomeInString(`gateway.remote.url: ${config.gateway.remote.url}`));
}
if (config.skills?.install?.nodeManager) {
rows.push(`skills.nodeManager: ${config.skills.install.nodeManager}`);
rows.push(shortenHomeInString(`skills.nodeManager: ${config.skills.install.nodeManager}`));
}
return rows.length ? rows.join("\n") : "No key settings detected.";
}
@@ -220,10 +226,10 @@ export async function ensureWorkspaceAndSessions(
dir: workspaceDir,
ensureBootstrapFiles: !options?.skipBootstrap,
});
runtime.log(`Workspace OK: ${ws.dir}`);
runtime.log(`Workspace OK: ${shortenHomePath(ws.dir)}`);
const sessionsDir = resolveSessionTranscriptsDirForAgent(options?.agentId);
await fs.mkdir(sessionsDir, { recursive: true });
runtime.log(`Sessions OK: ${sessionsDir}`);
runtime.log(`Sessions OK: ${shortenHomePath(sessionsDir)}`);
}
export function resolveNodeManagerOptions(): Array<{
@@ -246,9 +252,9 @@ export async function moveToTrash(pathname: string, runtime: RuntimeEnv): Promis
}
try {
await runCommandWithTimeout(["trash", pathname], { timeoutMs: 5000 });
runtime.log(`Moved to Trash: ${pathname}`);
runtime.log(`Moved to Trash: ${shortenHomePath(pathname)}`);
} catch {
runtime.log(`Failed to move to Trash (manual delete): ${pathname}`);
runtime.log(`Failed to move to Trash (manual delete): ${shortenHomePath(pathname)}`);
}
}

View File

@@ -2,6 +2,7 @@ import type { ClawdbotConfig } from "../../config/config.js";
import { CONFIG_PATH_CLAWDBOT, resolveGatewayPort, writeConfigFile } from "../../config/config.js";
import type { RuntimeEnv } from "../../runtime.js";
import { formatCliCommand } from "../../cli/command-format.js";
import { shortenHomePath } from "../../utils.js";
import { DEFAULT_GATEWAY_DAEMON_RUNTIME } from "../daemon-runtime.js";
import { healthCommand } from "../health.js";
import {
@@ -74,7 +75,7 @@ export async function runNonInteractiveOnboardingLocal(params: {
nextConfig = applyWizardMetadata(nextConfig, { command: "onboard", mode });
await writeConfigFile(nextConfig);
runtime.log(`Updated ${CONFIG_PATH_CLAWDBOT}`);
runtime.log(`Updated ${shortenHomePath(CONFIG_PATH_CLAWDBOT)}`);
await ensureWorkspaceAndSessions(workspaceDir, runtime, {
skipBootstrap: Boolean(nextConfig.agents?.defaults?.skipBootstrap),

View File

@@ -36,6 +36,7 @@ import {
import type { AuthChoice, OnboardOptions } from "../../onboard-types.js";
import { applyOpenAICodexModelDefault } from "../../openai-codex-model-default.js";
import { resolveNonInteractiveApiKey } from "../api-keys.js";
import { shortenHomePath } from "../../../utils.js";
export async function applyNonInteractiveAuthChoice(params: {
nextConfig: ClawdbotConfig;
@@ -172,7 +173,7 @@ export async function applyNonInteractiveAuthChoice(params: {
const key = resolved.key;
const result = upsertSharedEnvVar({ key: "OPENAI_API_KEY", value: key });
process.env.OPENAI_API_KEY = key;
runtime.log(`Saved OPENAI_API_KEY to ${result.path}`);
runtime.log(`Saved OPENAI_API_KEY to ${shortenHomePath(result.path)}`);
return nextConfig;
}

View File

@@ -4,6 +4,7 @@ import type { RuntimeEnv } from "../../runtime.js";
import { formatCliCommand } from "../../cli/command-format.js";
import { applyWizardMetadata } from "../onboard-helpers.js";
import type { OnboardOptions } from "../onboard-types.js";
import { shortenHomePath } from "../../utils.js";
export async function runNonInteractiveOnboardingRemote(params: {
opts: OnboardOptions;
@@ -33,7 +34,7 @@ export async function runNonInteractiveOnboardingRemote(params: {
};
nextConfig = applyWizardMetadata(nextConfig, { command: "onboard", mode });
await writeConfigFile(nextConfig);
runtime.log(`Updated ${CONFIG_PATH_CLAWDBOT}`);
runtime.log(`Updated ${shortenHomePath(CONFIG_PATH_CLAWDBOT)}`);
const payload = {
mode,

View File

@@ -7,6 +7,7 @@ import { type ClawdbotConfig, CONFIG_PATH_CLAWDBOT, writeConfigFile } from "../c
import { resolveSessionTranscriptsDir } from "../config/sessions.js";
import type { RuntimeEnv } from "../runtime.js";
import { defaultRuntime } from "../runtime.js";
import { shortenHomePath } from "../utils.js";
async function readConfigFileRaw(): Promise<{
exists: boolean;
@@ -54,20 +55,20 @@ export async function setupCommand(
await writeConfigFile(next);
runtime.log(
!existingRaw.exists
? `Wrote ${CONFIG_PATH_CLAWDBOT}`
: `Updated ${CONFIG_PATH_CLAWDBOT} (set agents.defaults.workspace)`,
? `Wrote ${shortenHomePath(CONFIG_PATH_CLAWDBOT)}`
: `Updated ${shortenHomePath(CONFIG_PATH_CLAWDBOT)} (set agents.defaults.workspace)`,
);
} else {
runtime.log(`Config OK: ${CONFIG_PATH_CLAWDBOT}`);
runtime.log(`Config OK: ${shortenHomePath(CONFIG_PATH_CLAWDBOT)}`);
}
const ws = await ensureAgentWorkspace({
dir: workspace,
ensureBootstrapFiles: !next.agents?.defaults?.skipBootstrap,
});
runtime.log(`Workspace OK: ${ws.dir}`);
runtime.log(`Workspace OK: ${shortenHomePath(ws.dir)}`);
const sessionsDir = resolveSessionTranscriptsDir();
await fs.mkdir(sessionsDir, { recursive: true });
runtime.log(`Sessions OK: ${sessionsDir}`);
runtime.log(`Sessions OK: ${shortenHomePath(sessionsDir)}`);
}