diff --git a/package.json b/package.json
index 65f7fef0..75bd7e70 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "better-clawd",
- "version": "0.1.1",
+ "version": "0.1.4",
"description": "Claude Code, but better.",
"type": "module",
"bin": {
diff --git a/scripts/build.ts b/scripts/build.ts
index 99d92490..d9cab81d 100644
--- a/scripts/build.ts
+++ b/scripts/build.ts
@@ -13,7 +13,7 @@ const result = await Bun.build({
minify: false,
naming: 'cli.mjs',
define: {
- 'MACRO.VERSION': JSON.stringify('99.0.0'),
+ 'MACRO.VERSION': JSON.stringify(version),
'MACRO.DISPLAY_VERSION': JSON.stringify(version),
'MACRO.BUILD_TIME': JSON.stringify(new Date().toISOString()),
'MACRO.ISSUES_EXPLAINER': JSON.stringify(
diff --git a/src/components/Onboarding.tsx b/src/components/Onboarding.tsx
index d4b62663..5bbb83cb 100644
--- a/src/components/Onboarding.tsx
+++ b/src/components/Onboarding.tsx
@@ -2,6 +2,7 @@ import { c as _c } from "react/compiler-runtime";
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { type AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, logEvent } from 'src/services/analytics/index.js';
import { setupTerminal, shouldOfferTerminalSetup } from '../commands/terminalSetup/terminalSetup.js';
+import { Login } from '../commands/login/login.js';
import { useExitOnCtrlCDWithKeybindings } from '../hooks/useExitOnCtrlCDWithKeybindings.js';
import { Box, Link, Newline, Text, useTheme } from '../ink.js';
import { useKeybindings } from '../keybindings/useKeybinding.js';
@@ -13,7 +14,6 @@ import { isRunningOnHomespace } from '../utils/envUtils.js';
import { PreflightStep } from '../utils/preflightChecks.js';
import type { ThemeSetting } from '../utils/theme.js';
import { ApproveApiKey } from './ApproveApiKey.js';
-import { ConsoleOAuthFlow } from './ConsoleOAuthFlow.js';
import { Select } from './CustomSelect/select.js';
import { WelcomeV2 } from './LogoV2/WelcomeV2.js';
import { PressEnterToContinue } from './PressEnterToContinue.js';
@@ -134,7 +134,13 @@ export function Onboarding({
steps.push({
id: 'oauth',
component:
-
+ {
+ if (success) {
+ goToNextStep();
+ }
+ }} />
});
}
diff --git a/src/constants/product.ts b/src/constants/product.ts
index bdc4f608..26043879 100644
--- a/src/constants/product.ts
+++ b/src/constants/product.ts
@@ -25,10 +25,7 @@ export const CLAUDE_AI_STAGING_BASE_URL = ANTHROPIC_APP_STAGING_BASE_URL
export const CLAUDE_AI_LOCAL_BASE_URL = ANTHROPIC_APP_LOCAL_BASE_URL
export function getConfiguredProductConfigDir(): string | undefined {
- return (
- process.env[PRODUCT_CONFIG_ENV_VAR] ??
- process.env[LEGACY_PRODUCT_CONFIG_ENV_VAR]
- )
+ return process.env[PRODUCT_CONFIG_ENV_VAR]
}
/**
diff --git a/src/main.tsx b/src/main.tsx
index 32119111..ca7faf72 100644
--- a/src/main.tsx
+++ b/src/main.tsx
@@ -27,7 +27,11 @@ import pickBy from 'lodash-es/pickBy.js';
import uniqBy from 'lodash-es/uniqBy.js';
import React from 'react';
import { getOauthConfig } from './constants/oauth.js';
-import { getRemoteSessionUrl } from './constants/product.js';
+import {
+ CLI_BINARY_NAME,
+ getRemoteSessionUrl,
+ PRODUCT_NAME,
+} from './constants/product.js';
import { getSystemContext, getUserContext } from './context.js';
import { init, initializeTelemetryAfterTrust } from './entrypoints/init.js';
import { addToHistory } from './history.js';
@@ -952,7 +956,7 @@ async function run(): Promise {
// terminal shell integration may mirror the process name to the tab.
// After init() so settings.json env can also gate this (gh-4765).
if (!isEnvTruthy(process.env.CLAUDE_CODE_DISABLE_TERMINAL_TITLE)) {
- process.title = 'claude';
+ process.title = CLI_BINARY_NAME;
}
// Attach logging sinks so subcommand handlers can use logEvent/logError.
@@ -997,7 +1001,7 @@ async function run(): Promise {
}
profileCheckpoint('preAction_after_settings_sync');
});
- program.name('claude').description(`Claude Code - starts an interactive session by default, use -p/--print for non-interactive output`).argument('[prompt]', 'Your prompt', String)
+ program.name(CLI_BINARY_NAME).description(`${PRODUCT_NAME} starts an interactive session by default. Use -p/--print for non-interactive output.`).argument('[prompt]', 'Your prompt', String)
// Subcommands inherit helpOption via commander's copyInheritedSettings —
// setting it once here covers mcp, plugin, auth, and all other subcommands.
.helpOption('-h, --help', 'Display help for command').option('-d, --debug [filter]', 'Enable debug mode with optional category filtering (e.g., "api,hooks" or "!1p,!file")', (_value: string | true) => {
@@ -1051,7 +1055,7 @@ async function run(): Promise {
if (prompt === 'code') {
logEvent('tengu_code_prompt_ignored', {});
// biome-ignore lint/suspicious/noConsole:: intentional console output
- console.warn(chalk.yellow('Tip: You can launch Claude Code with just `claude`'));
+ console.warn(chalk.yellow(`Tip: You can launch ${PRODUCT_NAME} with just \`${CLI_BINARY_NAME}\``));
prompt = undefined;
}
@@ -3835,7 +3839,7 @@ async function run(): Promise {
pendingHookMessages
}, renderAndRun);
}
- }).version(`${MACRO.VERSION} (Claude Code)`, '-v, --version', 'Output the version number');
+ }).version(`${MACRO.VERSION} (${PRODUCT_NAME})`, '-v, --version', 'Output the version number');
// Worktree flags
program.option('-w, --worktree [name]', 'Create a new git worktree for this session (optionally specify a name)');
diff --git a/src/screens/REPL.tsx b/src/screens/REPL.tsx
index 1fdf1e8e..2c9a55ca 100644
--- a/src/screens/REPL.tsx
+++ b/src/screens/REPL.tsx
@@ -68,6 +68,7 @@ import { useSkillImprovementSurvey } from '../hooks/useSkillImprovementSurvey.js
import { useMoreRight } from '../moreright/useMoreRight.js';
import { SpinnerWithVerb, BriefIdleStatus, type SpinnerMode } from '../components/Spinner.js';
import { getSystemPrompt } from '../constants/prompts.js';
+import { PRODUCT_CONFIG_DIRNAME, PRODUCT_NAME } from '../constants/product.js';
import { buildEffectiveSystemPrompt } from '../utils/systemPrompt.js';
import { getSystemContext, getUserContext } from '../context.js';
import { getMemoryFiles } from '../utils/claudemd.js';
@@ -1176,7 +1177,7 @@ export function REPL({
// session from mid-conversation context.
const haikuTitleAttemptedRef = useRef((initialMessages?.length ?? 0) > 0);
const agentTitle = mainThreadAgentDefinition?.agentType;
- const terminalTitle = sessionTitle ?? agentTitle ?? haikuTitle ?? 'Claude Code';
+ const terminalTitle = sessionTitle ?? agentTitle ?? haikuTitle ?? PRODUCT_NAME;
const isWaitingForApproval = toolUseConfirmQueue.length > 0 || promptQueue.length > 0 || pendingWorkerRequest || pendingSandboxRequest;
// Local-jsx commands (like /plugin, /config) show user-facing dialogs that
// wait for input. Require jsx != null — if the flag is stuck true but jsx
@@ -1692,7 +1693,7 @@ export function REPL({
if (wt.creationDurationMs < 15_000) return;
worktreeTipShownRef.current = true;
const secs = Math.round(wt.creationDurationMs / 1000);
- setMessages(prev => [...prev, createSystemMessage(`Worktree creation took ${secs}s. For large repos, set \`worktree.sparsePaths\` in .claude/settings.json to check out only the directories you need — e.g. \`{"worktree": {"sparsePaths": ["src", "packages/foo"]}}\`.`, 'info')]);
+ setMessages(prev => [...prev, createSystemMessage(`Worktree creation took ${secs}s. For large repos, set \`worktree.sparsePaths\` in \`${PRODUCT_CONFIG_DIRNAME}/settings.json\` to check out only the directories you need — e.g. \`{"worktree": {"sparsePaths": ["src", "packages/foo"]}}\`.`, 'info')]);
}, [setMessages]);
// Hide spinner when the only in-progress tool is Sleep
@@ -4193,7 +4194,7 @@ export function REPL({
useEffect(() => {
const handleSuspend = () => {
// Print suspension instructions
- process.stdout.write(`\nClaude Code has been suspended. Run \`fg\` to bring Claude Code back.\nNote: ctrl + z now suspends Claude Code, ctrl + _ undoes input.\n`);
+ process.stdout.write(`\n${PRODUCT_NAME} has been suspended. Run \`fg\` to bring ${PRODUCT_NAME} back.\nNote: ctrl + z now suspends ${PRODUCT_NAME}, ctrl + _ undoes input.\n`);
};
const handleResume = () => {
// Force complete component tree replacement instead of terminal clear
diff --git a/src/utils/env.ts b/src/utils/env.ts
index bfaa40fe..3d038919 100644
--- a/src/utils/env.ts
+++ b/src/utils/env.ts
@@ -3,12 +3,11 @@ import { homedir } from 'os'
import { join } from 'path'
import {
getConfiguredProductConfigDir,
- LEGACY_PRODUCT_SLUG,
PRODUCT_SLUG,
} from '../constants/product.js'
import { fileSuffixForOauthConfig } from '../constants/oauth.js'
import { isRunningWithBun } from './bundledMode.js'
-import { getClaudeConfigHomeDir, isEnvTruthy } from './envUtils.js'
+import { isEnvTruthy } from './envUtils.js'
import { findExecutable } from './findExecutable.js'
import { getFsImplementation } from './fsOperations.js'
import { which } from './which.js'
@@ -17,27 +16,15 @@ type Platform = 'win32' | 'darwin' | 'linux'
// Config and data paths
export const getGlobalClaudeFile = memoize((): string => {
- const configHomeDir = getClaudeConfigHomeDir()
const configDirOverride = getConfiguredProductConfigDir()
- // Legacy fallback for backwards compatibility
- const legacyConfigPath = join(configHomeDir, '.config.json')
- if (getFsImplementation().existsSync(legacyConfigPath)) {
- return legacyConfigPath
- }
-
const suffix = fileSuffixForOauthConfig()
const preferredFilename = `.${PRODUCT_SLUG}${suffix}.json`
- const legacyFilename = `.${LEGACY_PRODUCT_SLUG}${suffix}.json`
const preferredPath = join(configDirOverride || homedir(), preferredFilename)
- const legacyPath = join(configDirOverride || homedir(), legacyFilename)
if (getFsImplementation().existsSync(preferredPath)) {
return preferredPath
}
- if (getFsImplementation().existsSync(legacyPath)) {
- return legacyPath
- }
return preferredPath
})
diff --git a/src/utils/envUtils.ts b/src/utils/envUtils.ts
index 3f65f52f..94cf248e 100644
--- a/src/utils/envUtils.ts
+++ b/src/utils/envUtils.ts
@@ -4,12 +4,11 @@ import { homedir } from 'os'
import { join } from 'path'
import {
getConfiguredProductConfigDir,
- LEGACY_PRODUCT_CONFIG_DIRNAME,
PRODUCT_CONFIG_DIRNAME,
} from '../constants/product.js'
-// Memoized: 150+ callers, many on hot paths. Keyed off CLAUDE_CONFIG_DIR so
-// tests that change the env var get a fresh value without explicit cache.clear.
+// Memoized: 150+ callers, many on hot paths. Keyed off BETTER_CLAWD_CONFIG_DIR
+// so tests that change the env var get a fresh value without explicit cache.clear.
export const getClaudeConfigHomeDir = memoize(
(): string => {
const configuredDir = getConfiguredProductConfigDir()
@@ -18,14 +17,10 @@ export const getClaudeConfigHomeDir = memoize(
}
const betterClawdDir = join(homedir(), PRODUCT_CONFIG_DIRNAME)
- const legacyClaudeDir = join(homedir(), LEGACY_PRODUCT_CONFIG_DIRNAME)
if (existsSync(betterClawdDir)) {
return betterClawdDir.normalize('NFC')
}
- if (existsSync(legacyClaudeDir)) {
- return legacyClaudeDir.normalize('NFC')
- }
return betterClawdDir.normalize('NFC')
},
diff --git a/src/utils/secureStorage/macOsKeychainHelpers.ts b/src/utils/secureStorage/macOsKeychainHelpers.ts
index cd07550a..3397bcbd 100644
--- a/src/utils/secureStorage/macOsKeychainHelpers.ts
+++ b/src/utils/secureStorage/macOsKeychainHelpers.ts
@@ -19,7 +19,6 @@ import { userInfo } from 'os'
import { getOauthConfig } from 'src/constants/oauth.js'
import {
getConfiguredProductConfigDir,
- LEGACY_PRODUCT_NAME,
PRODUCT_NAME,
} from 'src/constants/product.js'
import { getClaudeConfigHomeDir } from '../envUtils.js'
@@ -33,7 +32,6 @@ export const CREDENTIALS_SERVICE_SUFFIX = '-credentials'
export function getMacOsKeychainStorageServiceName(
serviceSuffix: string = '',
- opts: { legacy?: boolean } = {},
): string {
const configDir = getClaudeConfigHomeDir()
const isDefaultDir = !getConfiguredProductConfigDir()
@@ -43,18 +41,13 @@ export function getMacOsKeychainStorageServiceName(
const dirHash = isDefaultDir
? ''
: `-${createHash('sha256').update(configDir).digest('hex').substring(0, 8)}`
- const baseName = opts.legacy ? LEGACY_PRODUCT_NAME : PRODUCT_NAME
- return `${baseName}${getOauthConfig().OAUTH_FILE_SUFFIX}${serviceSuffix}${dirHash}`
+ return `${PRODUCT_NAME}${getOauthConfig().OAUTH_FILE_SUFFIX}${serviceSuffix}${dirHash}`
}
export function getMacOsKeychainStorageServiceNames(
serviceSuffix: string = '',
): string[] {
- const names = [
- getMacOsKeychainStorageServiceName(serviceSuffix),
- getMacOsKeychainStorageServiceName(serviceSuffix, { legacy: true }),
- ]
- return Array.from(new Set(names))
+ return [getMacOsKeychainStorageServiceName(serviceSuffix)]
}
export function getUsername(): string {