fix: prefer ~ for home paths in output
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)}`);
|
||||
}
|
||||
|
||||
@@ -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}`);
|
||||
|
||||
|
||||
@@ -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 };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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)");
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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.`);
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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)})`,
|
||||
|
||||
@@ -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.");
|
||||
}
|
||||
|
||||
@@ -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.");
|
||||
}
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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(", ")}`);
|
||||
|
||||
@@ -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}`);
|
||||
}
|
||||
|
||||
@@ -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}`);
|
||||
}
|
||||
|
||||
@@ -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)}`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)}`);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user