feat: rebrand as Open Claude and harden OpenAI REPL
This commit is contained in:
@@ -52,8 +52,11 @@ const result = await Bun.build({
|
||||
naming: 'cli.mjs',
|
||||
define: {
|
||||
// MACRO.* build-time constants
|
||||
// Set version high enough to pass minimum version checks
|
||||
// Keep the internal compatibility version high enough to pass
|
||||
// first-party minimum-version guards, but expose the real package
|
||||
// version separately in Open Claude branding.
|
||||
'MACRO.VERSION': JSON.stringify('99.0.0'),
|
||||
'MACRO.DISPLAY_VERSION': JSON.stringify(version),
|
||||
'MACRO.BUILD_TIME': JSON.stringify(new Date().toISOString()),
|
||||
'MACRO.ISSUES_EXPLAINER':
|
||||
JSON.stringify('report the issue at https://github.com/anthropics/claude-code/issues'),
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -115,6 +115,7 @@ export default class App extends PureComponent<Props, State> {
|
||||
keyParseState = INITIAL_STATE;
|
||||
// Timer for flushing incomplete escape sequences
|
||||
incompleteEscapeTimer: NodeJS.Timeout | null = null;
|
||||
stdinMode: 'readable' | 'data' = process.env.OPENCLAUDE_USE_READABLE_STDIN === '1' ? 'readable' : 'data';
|
||||
// Timeout durations for incomplete sequences (ms)
|
||||
readonly NORMAL_TIMEOUT = 50; // Short timeout for regular esc sequences
|
||||
readonly PASTE_TIMEOUT = 500; // Longer timeout for paste operations
|
||||
@@ -228,7 +229,12 @@ export default class App extends PureComponent<Props, State> {
|
||||
stopCapturingEarlyInput();
|
||||
stdin.ref();
|
||||
stdin.setRawMode(true);
|
||||
stdin.addListener('readable', this.handleReadable);
|
||||
stdin.resume();
|
||||
if (this.stdinMode === 'data') {
|
||||
stdin.addListener('data', this.handleDataChunk);
|
||||
} else {
|
||||
stdin.addListener('readable', this.handleReadable);
|
||||
}
|
||||
// Enable bracketed paste mode
|
||||
this.props.stdout.write(EBP);
|
||||
// Enable terminal focus reporting (DECSET 1004)
|
||||
@@ -275,6 +281,8 @@ export default class App extends PureComponent<Props, State> {
|
||||
this.props.stdout.write(DBP);
|
||||
stdin.setRawMode(false);
|
||||
stdin.removeListener('readable', this.handleReadable);
|
||||
stdin.removeListener('data', this.handleDataChunk);
|
||||
stdin.pause();
|
||||
stdin.unref();
|
||||
}
|
||||
};
|
||||
@@ -366,6 +374,27 @@ export default class App extends PureComponent<Props, State> {
|
||||
}
|
||||
}
|
||||
};
|
||||
handleDataChunk = (chunk: string | Buffer): void => {
|
||||
const now = Date.now();
|
||||
if (now - this.lastStdinTime > STDIN_RESUME_GAP_MS) {
|
||||
this.props.onStdinResume?.();
|
||||
}
|
||||
this.lastStdinTime = now;
|
||||
try {
|
||||
this.processInput(chunk);
|
||||
} catch (error) {
|
||||
logError(error);
|
||||
const {
|
||||
stdin
|
||||
} = this.props;
|
||||
if (this.rawModeEnabledCount > 0 && !stdin.listeners('data').includes(this.handleDataChunk)) {
|
||||
logForDebugging('handleDataChunk: re-attaching stdin data listener after error recovery', {
|
||||
level: 'warn'
|
||||
});
|
||||
stdin.addListener('data', this.handleDataChunk);
|
||||
}
|
||||
}
|
||||
};
|
||||
handleInput = (input: string | undefined): void => {
|
||||
// Exit on Ctrl+C
|
||||
if (input === '\x03' && this.props.exitOnCtrlC) {
|
||||
|
||||
@@ -165,6 +165,12 @@ const EXTENDED_KEYS_TERMINALS = [
|
||||
/** True if this terminal correctly handles extended key reporting
|
||||
* (Kitty keyboard protocol + xterm modifyOtherKeys). */
|
||||
export function supportsExtendedKeys(): boolean {
|
||||
// Open Claude defaults this off because some real terminals render the UI
|
||||
// but stop delivering normal typing once kitty/modifyOtherKeys negotiation
|
||||
// is enabled. Power users can opt back in explicitly.
|
||||
if (process.env.OPENCLAUDE_ENABLE_EXTENDED_KEYS !== '1') {
|
||||
return false
|
||||
}
|
||||
return EXTENDED_KEYS_TERMINALS.includes(env.terminal ?? '')
|
||||
}
|
||||
|
||||
|
||||
@@ -3782,7 +3782,7 @@ async function run(): Promise<CommanderCommand> {
|
||||
pendingHookMessages
|
||||
}, renderAndRun);
|
||||
}
|
||||
}).version(`${MACRO.VERSION} (Claude Code)`, '-v, --version', 'Output the version number');
|
||||
}).version(`${MACRO.DISPLAY_VERSION ?? MACRO.VERSION} (Open Claude)`, '-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)');
|
||||
|
||||
@@ -217,6 +217,7 @@ import { IdeOnboardingDialog } from '../components/IdeOnboardingDialog.js';
|
||||
import { EffortCallout, shouldShowEffortCallout } from '../components/EffortCallout.js';
|
||||
import type { EffortValue } from '../utils/effort.js';
|
||||
import { RemoteCallout } from '../components/RemoteCallout.js';
|
||||
import { getAPIProvider } from '../utils/model/providers.js';
|
||||
/* eslint-disable custom-rules/no-process-env-top-level, @typescript-eslint/no-require-imports */
|
||||
const AntModelSwitchCallout = "external" === 'ant' ? require('../components/AntModelSwitchCallout.js').AntModelSwitchCallout : null;
|
||||
const shouldShowAntModelSwitch = "external" === 'ant' ? require('../components/AntModelSwitchCallout.js').shouldShowModelSwitchCallout : (): boolean => false;
|
||||
@@ -2675,7 +2676,7 @@ export function REPL({
|
||||
// useDeferredHookMessages) and attachment messages (appended by
|
||||
// processTextPrompt) — both pushed length past 1 on turn one, so the
|
||||
// title silently fell through to the "Claude Code" default.
|
||||
if (!titleDisabled && !sessionTitle && !agentTitle && !haikuTitleAttemptedRef.current) {
|
||||
if (getAPIProvider() === 'firstParty' && !titleDisabled && !sessionTitle && !agentTitle && !haikuTitleAttemptedRef.current) {
|
||||
const firstUserMessage = newMessages.find(m => m.type === 'user' && !m.isMeta);
|
||||
const text = firstUserMessage?.type === 'user' ? getContentText(firstUserMessage.message.content) : null;
|
||||
// Skip synthetic breadcrumbs — slash-command output, prompt-skill
|
||||
|
||||
@@ -7,6 +7,7 @@ import { getModelBetas } from '../utils/betas.js'
|
||||
import { getGlobalConfig, saveGlobalConfig } from '../utils/config.js'
|
||||
import { logError } from '../utils/log.js'
|
||||
import { getSmallFastModel } from '../utils/model/model.js'
|
||||
import { getAPIProvider } from '../utils/model/providers.js'
|
||||
import { isEssentialTrafficOnly } from '../utils/privacyLevel.js'
|
||||
import type { AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS } from './analytics/index.js'
|
||||
import { logEvent } from './analytics/index.js'
|
||||
@@ -223,6 +224,10 @@ export async function checkQuotaStatus(): Promise<void> {
|
||||
return
|
||||
}
|
||||
|
||||
if (getAPIProvider() !== 'firstParty') {
|
||||
return
|
||||
}
|
||||
|
||||
// Check if we should process rate limits (real subscriber or mock testing)
|
||||
if (!shouldProcessRateLimits(isClaudeAISubscriber())) {
|
||||
return
|
||||
|
||||
@@ -9,6 +9,7 @@ import { getClaudeAIOAuthTokens } from 'src/utils/auth.js'
|
||||
import { getGlobalConfig, saveGlobalConfig } from 'src/utils/config.js'
|
||||
import { logForDebugging } from 'src/utils/debug.js'
|
||||
import { isEnvDefinedFalsy } from 'src/utils/envUtils.js'
|
||||
import { getAPIProvider } from 'src/utils/model/providers.js'
|
||||
import { clearMcpAuthCache } from './client.js'
|
||||
import { normalizeNameForMCP } from './normalization.js'
|
||||
import type { ScopedMcpServerConfig } from './types.js'
|
||||
@@ -39,6 +40,15 @@ const MCP_SERVERS_BETA_HEADER = 'mcp-servers-2025-12-04'
|
||||
export const fetchClaudeAIMcpConfigsIfEligible = memoize(
|
||||
async (): Promise<Record<string, ScopedMcpServerConfig>> => {
|
||||
try {
|
||||
if (getAPIProvider() !== 'firstParty') {
|
||||
logForDebugging('[claudeai-mcp] Skipped: non-first-party provider')
|
||||
logEvent('tengu_claudeai_mcp_eligibility', {
|
||||
state:
|
||||
'non_first_party_provider' as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
|
||||
})
|
||||
return {}
|
||||
}
|
||||
|
||||
if (isEnvDefinedFalsy(process.env.ENABLE_CLAUDEAI_MCP_SERVERS)) {
|
||||
logForDebugging('[claudeai-mcp] Disabled via env var')
|
||||
logEvent('tengu_claudeai_mcp_eligibility', {
|
||||
|
||||
@@ -109,7 +109,7 @@ export function execFileNoThrowWithCwd(
|
||||
// Use execa for cross-platform .bat/.cmd compatibility on Windows
|
||||
execa(file, args, {
|
||||
maxBuffer,
|
||||
signal: abortSignal,
|
||||
cancelSignal: abortSignal,
|
||||
timeout: finalTimeout,
|
||||
cwd: finalCwd,
|
||||
env: finalEnv,
|
||||
|
||||
@@ -36,6 +36,9 @@ import {
|
||||
import { createSignal } from './signal.js'
|
||||
|
||||
export function isFastModeEnabled(): boolean {
|
||||
if (getAPIProvider() !== 'firstParty') {
|
||||
return false
|
||||
}
|
||||
return !isEnvTruthy(process.env.CLAUDE_CODE_DISABLE_FAST_MODE)
|
||||
}
|
||||
|
||||
@@ -70,6 +73,10 @@ function getDisabledReasonMessage(
|
||||
}
|
||||
|
||||
export function getFastModeUnavailableReason(): string | null {
|
||||
if (getAPIProvider() !== 'firstParty') {
|
||||
return 'Fast mode is not available on third-party providers'
|
||||
}
|
||||
|
||||
if (!isFastModeEnabled()) {
|
||||
return 'Fast mode is not available'
|
||||
}
|
||||
@@ -109,13 +116,6 @@ export function getFastModeUnavailableReason(): string | null {
|
||||
}
|
||||
}
|
||||
|
||||
// Only available for 1P (not Bedrock/Vertex/Foundry)
|
||||
if (getAPIProvider() !== 'firstParty') {
|
||||
const reason = 'Fast mode is not available on Bedrock, Vertex, or Foundry'
|
||||
logForDebugging(`Fast mode unavailable: ${reason}`)
|
||||
return reason
|
||||
}
|
||||
|
||||
if (orgStatus.status === 'disabled') {
|
||||
if (
|
||||
orgStatus.reason === 'network_error' ||
|
||||
|
||||
@@ -245,7 +245,7 @@ export function getLogoDisplayData(): {
|
||||
billingType: string
|
||||
agentName: string | undefined
|
||||
} {
|
||||
const version = process.env.DEMO_VERSION ?? MACRO.VERSION
|
||||
const version = process.env.DEMO_VERSION ?? MACRO.DISPLAY_VERSION ?? MACRO.VERSION
|
||||
const serverUrl = getDirectConnectServerUrl()
|
||||
const displayPath = process.env.DEMO_VERSION
|
||||
? '/code/claude'
|
||||
|
||||
Reference in New Issue
Block a user