fix: 批量修正 external 字面量

This commit is contained in:
claude-code-best 2026-04-02 17:01:39 +08:00
parent 799dacc407
commit ac1f02958c
31 changed files with 97 additions and 100 deletions

View File

@ -10,12 +10,12 @@ import { getRainbowColor } from '../utils/thinking.js';
// buzz instead of a single UTC-midnight spike, gentler on soul-gen load. // buzz instead of a single UTC-midnight spike, gentler on soul-gen load.
// Teaser window: April 1-7, 2026 only. Command stays live forever after. // Teaser window: April 1-7, 2026 only. Command stays live forever after.
export function isBuddyTeaserWindow(): boolean { export function isBuddyTeaserWindow(): boolean {
if (("external" as string) === 'ant') return true; if ((process.env.USER_TYPE) === 'ant') return true;
const d = new Date(); const d = new Date();
return d.getFullYear() === 2026 && d.getMonth() === 3 && d.getDate() <= 7; return d.getFullYear() === 2026 && d.getMonth() === 3 && d.getDate() <= 7;
} }
export function isBuddyLive(): boolean { export function isBuddyLive(): boolean {
if (("external" as string) === 'ant') return true; if ((process.env.USER_TYPE) === 'ant') return true;
const d = new Date(); const d = new Date();
return d.getFullYear() > 2026 || d.getFullYear() === 2026 && d.getMonth() >= 3; return d.getFullYear() > 2026 || d.getFullYear() === 2026 && d.getMonth() >= 3;
} }

View File

@ -77,7 +77,7 @@ export async function call(onDone: LocalJSXCommandOnDone, _context: unknown, arg
} }
// Redirect base /mcp command to /plugins installed tab for ant users // Redirect base /mcp command to /plugins installed tab for ant users
if (("external" as string) === 'ant') { if ((process.env.USER_TYPE) === 'ant') {
return <PluginSettings onComplete={onDone} args="manage" showMcpRedirectMessage />; return <PluginSettings onComplete={onDone} args="manage" showMcpRedirectMessage />;
} }
return <MCPSettings onComplete={onDone} />; return <MCPSettings onComplete={onDone} />;

View File

@ -119,7 +119,7 @@ export async function setupTerminal(theme: ThemeName): Promise<string> {
maybeMarkProjectOnboardingComplete(); maybeMarkProjectOnboardingComplete();
// Install shell completions (ant-only, since the completion command is ant-only) // Install shell completions (ant-only, since the completion command is ant-only)
if (("external" as string) === 'ant') { if ((process.env.USER_TYPE) === 'ant') {
result += await setupShellCompletion(theme); result += await setupShellCompletion(theme);
} }
return result; return result;

View File

@ -29,10 +29,10 @@ const INTERNAL_MARKETPLACE_NAME = 'claude-code-marketplace';
const INTERNAL_MARKETPLACE_REPO = 'anthropics/claude-code-marketplace'; const INTERNAL_MARKETPLACE_REPO = 'anthropics/claude-code-marketplace';
const OFFICIAL_MARKETPLACE_REPO = 'anthropics/claude-plugins-official'; const OFFICIAL_MARKETPLACE_REPO = 'anthropics/claude-plugins-official';
function getMarketplaceName(): string { function getMarketplaceName(): string {
return ("external" as string) === 'ant' ? INTERNAL_MARKETPLACE_NAME : OFFICIAL_MARKETPLACE_NAME; return (process.env.USER_TYPE) === 'ant' ? INTERNAL_MARKETPLACE_NAME : OFFICIAL_MARKETPLACE_NAME;
} }
function getMarketplaceRepo(): string { function getMarketplaceRepo(): string {
return ("external" as string) === 'ant' ? INTERNAL_MARKETPLACE_REPO : OFFICIAL_MARKETPLACE_REPO; return (process.env.USER_TYPE) === 'ant' ? INTERNAL_MARKETPLACE_REPO : OFFICIAL_MARKETPLACE_REPO;
} }
function getPluginId(): string { function getPluginId(): string {
return `thinkback@${getMarketplaceName()}`; return `thinkback@${getMarketplaceName()}`;

View File

@ -53,7 +53,7 @@ const DEFAULT_INSTRUCTIONS: string = (typeof _rawPrompt === 'string' ? _rawPromp
// Shell-set env only, so top-level process.env read is fine // Shell-set env only, so top-level process.env read is fine
// — settings.env never injects this. // — settings.env never injects this.
/* eslint-disable custom-rules/no-process-env-top-level, custom-rules/no-sync-fs -- ant-only dev override; eager top-level read is the point (crash at startup, not silently inside the slash-command try/catch) */ /* eslint-disable custom-rules/no-process-env-top-level, custom-rules/no-sync-fs -- ant-only dev override; eager top-level read is the point (crash at startup, not silently inside the slash-command try/catch) */
const ULTRAPLAN_INSTRUCTIONS: string = ("external" as string) === 'ant' && process.env.ULTRAPLAN_PROMPT_FILE ? readFileSync(process.env.ULTRAPLAN_PROMPT_FILE, 'utf8').trimEnd() : DEFAULT_INSTRUCTIONS; const ULTRAPLAN_INSTRUCTIONS: string = (process.env.USER_TYPE) === 'ant' && process.env.ULTRAPLAN_PROMPT_FILE ? readFileSync(process.env.ULTRAPLAN_PROMPT_FILE, 'utf8').trimEnd() : DEFAULT_INSTRUCTIONS;
/* eslint-enable custom-rules/no-process-env-top-level, custom-rules/no-sync-fs */ /* eslint-enable custom-rules/no-process-env-top-level, custom-rules/no-sync-fs */
/** /**
@ -464,7 +464,7 @@ export default {
name: 'ultraplan', name: 'ultraplan',
description: `~1030 min · Claude Code on the web drafts an advanced plan you can edit and approve. See ${CCR_TERMS_URL}`, description: `~1030 min · Claude Code on the web drafts an advanced plan you can edit and approve. See ${CCR_TERMS_URL}`,
argumentHint: '<prompt>', argumentHint: '<prompt>',
isEnabled: () => ("external" as string) === 'ant', isEnabled: () => (process.env.USER_TYPE) === 'ant',
load: () => Promise.resolve({ load: () => Promise.resolve({
call call
}) })

View File

@ -6,7 +6,7 @@ import { Text, useInterval } from '../ink.js';
// Show DevBar for dev builds or all ants // Show DevBar for dev builds or all ants
function shouldShowDevBar(): boolean { function shouldShowDevBar(): boolean {
return ("production" as string) === 'development' || ("external" as string) === 'ant'; return ("production" as string) === 'development' || (process.env.USER_TYPE) === 'ant';
} }
export function DevBar() { export function DevBar() {
const $ = _c(5); const $ = _c(5);

View File

@ -32,7 +32,7 @@ import TextInput from './TextInput.js';
// This value was determined experimentally by testing the URL length limit // This value was determined experimentally by testing the URL length limit
const GITHUB_URL_LIMIT = 7250; const GITHUB_URL_LIMIT = 7250;
const GITHUB_ISSUES_REPO_URL = ("external" as string) === 'ant' ? 'https://github.com/anthropics/claude-cli-internal/issues' : 'https://github.com/anthropics/claude-code/issues'; const GITHUB_ISSUES_REPO_URL = (process.env.USER_TYPE) === 'ant' ? 'https://github.com/anthropics/claude-cli-internal/issues' : 'https://github.com/anthropics/claude-code/issues';
type Props = { type Props = {
abortSignal: AbortSignal; abortSignal: AbortSignal;
messages: Message[]; messages: Message[];

View File

@ -87,7 +87,7 @@ export function useMemorySurvey(messages: Message[], isLoading: boolean, hasActi
}); });
}, []); }, []);
const shouldShowTranscriptPrompt = useCallback((selected_0: FeedbackSurveyResponse) => { const shouldShowTranscriptPrompt = useCallback((selected_0: FeedbackSurveyResponse) => {
if (("external" as string) !== 'ant') { if ((process.env.USER_TYPE) !== 'ant') {
return false; return false;
} }
if (selected_0 !== 'bad' && selected_0 !== 'good') { if (selected_0 !== 'bad' && selected_0 !== 'good') {

View File

@ -26,7 +26,7 @@ export function createRecentActivityFeed(activities: LogOption[]): FeedConfig {
} }
export function createWhatsNewFeed(releaseNotes: string[]): FeedConfig { export function createWhatsNewFeed(releaseNotes: string[]): FeedConfig {
const lines: FeedLine[] = releaseNotes.map(note => { const lines: FeedLine[] = releaseNotes.map(note => {
if (("external" as string) === 'ant') { if ((process.env.USER_TYPE) === 'ant') {
const match = note.match(/^(\d+\s+\w+\s+ago)\s+(.+)$/); const match = note.match(/^(\d+\s+\w+\s+ago)\s+(.+)$/);
if (match) { if (match) {
return { return {
@ -39,9 +39,9 @@ export function createWhatsNewFeed(releaseNotes: string[]): FeedConfig {
text: note text: note
}; };
}); });
const emptyMessage = ("external" as string) === 'ant' ? 'Unable to fetch latest claude-cli-internal commits' : 'Check the Claude Code changelog for updates'; const emptyMessage = (process.env.USER_TYPE) === 'ant' ? 'Unable to fetch latest claude-cli-internal commits' : 'Check the Claude Code changelog for updates';
return { return {
title: ("external" as string) === 'ant' ? "What's new [ANT-ONLY: Latest CC commits]" : "What's new", title: (process.env.USER_TYPE) === 'ant' ? "What's new [ANT-ONLY: Latest CC commits]" : "What's new",
lines, lines,
footer: lines.length > 0 ? '/release-notes for more' : undefined, footer: lines.length > 0 ? '/release-notes for more' : undefined,
emptyMessage emptyMessage

View File

@ -7,7 +7,7 @@ export function MemoryUsageIndicator(): React.ReactNode {
// the hook means the 10s polling interval is never set up in external builds. // the hook means the 10s polling interval is never set up in external builds.
// USER_TYPE is a build-time constant, so the hook call below is either always // USER_TYPE is a build-time constant, so the hook call below is either always
// reached or dead-code-eliminated — never conditional at runtime. // reached or dead-code-eliminated — never conditional at runtime.
if (("external" as string) !== 'ant') { if ((process.env.USER_TYPE) !== 'ant') {
return null; return null;
} }

View File

@ -118,7 +118,7 @@ export function MessageSelector({
...summarizeInputProps, ...summarizeInputProps,
onChange: setSummarizeFromFeedback onChange: setSummarizeFromFeedback
}); });
if (("external" as string) === 'ant') { if ((process.env.USER_TYPE) === 'ant') {
baseOptions.push({ baseOptions.push({
value: 'summarize_up_to', value: 'summarize_up_to',
label: 'Summarize up to here', label: 'Summarize up to here',

View File

@ -184,7 +184,7 @@ export function NativeAutoUpdater({
{autoUpdaterResult?.status === 'install_failed' && <Text color="error" wrap="truncate"> {autoUpdaterResult?.status === 'install_failed' && <Text color="error" wrap="truncate">
Auto-update failed &middot; Try <Text bold>/status</Text> Auto-update failed &middot; Try <Text bold>/status</Text>
</Text>} </Text>}
{maxVersionIssue && ("external" as string) === 'ant' && <Text color="warning"> {maxVersionIssue && (process.env.USER_TYPE) === 'ant' && <Text color="warning">
Known issue: {maxVersionIssue} &middot; Run{' '} Known issue: {maxVersionIssue} &middot; Run{' '}
<Text bold>claude rollback --safe</Text> to downgrade <Text bold>claude rollback --safe</Text> to downgrade
</Text>} </Text>}

View File

@ -294,8 +294,8 @@ function PromptInput({
// otherwise bridge becomes an invisible selection stop. // otherwise bridge becomes an invisible selection stop.
const bridgeFooterVisible = replBridgeConnected && (replBridgeExplicit || replBridgeReconnecting); const bridgeFooterVisible = replBridgeConnected && (replBridgeExplicit || replBridgeReconnecting);
// Tmux pill (ant-only) — visible when there's an active tungsten session // Tmux pill (ant-only) — visible when there's an active tungsten session
const hasTungstenSession = useAppState(s => ("external" as string) === 'ant' && s.tungstenActiveSession !== undefined); const hasTungstenSession = useAppState(s => (process.env.USER_TYPE) === 'ant' && s.tungstenActiveSession !== undefined);
const tmuxFooterVisible = ("external" as string) === 'ant' && hasTungstenSession; const tmuxFooterVisible = (process.env.USER_TYPE) === 'ant' && hasTungstenSession;
// WebBrowser pill — visible when a browser is open // WebBrowser pill — visible when a browser is open
const bagelFooterVisible = useAppState(s => false); const bagelFooterVisible = useAppState(s => false);
const teamContext = useAppState(s => s.teamContext); const teamContext = useAppState(s => s.teamContext);
@ -391,7 +391,7 @@ function PromptInput({
// exist. When only local_agent tasks are running (coordinator/fork mode), the // exist. When only local_agent tasks are running (coordinator/fork mode), the
// pill is absent, so the -1 sentinel would leave nothing visually selected. // pill is absent, so the -1 sentinel would leave nothing visually selected.
// In that case, skip -1 and treat 0 as the minimum selectable index. // In that case, skip -1 and treat 0 as the minimum selectable index.
const hasBgTaskPill = useMemo(() => Object.values(tasks).some(t => isBackgroundTask(t) && !(("external" as string) === 'ant' && isPanelAgentTask(t))), [tasks]); const hasBgTaskPill = useMemo(() => Object.values(tasks).some(t => isBackgroundTask(t) && !((process.env.USER_TYPE) === 'ant' && isPanelAgentTask(t))), [tasks]);
const minCoordinatorIndex = hasBgTaskPill ? -1 : 0; const minCoordinatorIndex = hasBgTaskPill ? -1 : 0;
// Clamp index when tasks complete and the list shrinks beneath the cursor // Clamp index when tasks complete and the list shrinks beneath the cursor
useEffect(() => { useEffect(() => {
@ -455,7 +455,7 @@ function PromptInput({
// Panel shows retained-completed agents too (getVisibleAgentTasks), so the // Panel shows retained-completed agents too (getVisibleAgentTasks), so the
// pill must stay navigable whenever the panel has rows — not just when // pill must stay navigable whenever the panel has rows — not just when
// something is running. // something is running.
const tasksFooterVisible = (runningTaskCount > 0 || ("external" as string) === 'ant' && coordinatorTaskCount > 0) && !shouldHideTasksFooter(tasks, showSpinnerTree); const tasksFooterVisible = (runningTaskCount > 0 || (process.env.USER_TYPE) === 'ant' && coordinatorTaskCount > 0) && !shouldHideTasksFooter(tasks, showSpinnerTree);
const teamsFooterVisible = cachedTeams.length > 0; const teamsFooterVisible = cachedTeams.length > 0;
const footerItems = useMemo(() => [tasksFooterVisible && 'tasks', tmuxFooterVisible && 'tmux', bagelFooterVisible && 'bagel', teamsFooterVisible && 'teams', bridgeFooterVisible && 'bridge', companionFooterVisible && 'companion'].filter(Boolean) as FooterItem[], [tasksFooterVisible, tmuxFooterVisible, bagelFooterVisible, teamsFooterVisible, bridgeFooterVisible, companionFooterVisible]); const footerItems = useMemo(() => [tasksFooterVisible && 'tasks', tmuxFooterVisible && 'tmux', bagelFooterVisible && 'bagel', teamsFooterVisible && 'teams', bridgeFooterVisible && 'bridge', companionFooterVisible && 'companion'].filter(Boolean) as FooterItem[], [tasksFooterVisible, tmuxFooterVisible, bagelFooterVisible, teamsFooterVisible, bridgeFooterVisible, companionFooterVisible]);
@ -1742,7 +1742,7 @@ function PromptInput({
useKeybindings({ useKeybindings({
'footer:up': () => { 'footer:up': () => {
// ↑ scrolls within the coordinator task list before leaving the pill // ↑ scrolls within the coordinator task list before leaving the pill
if (tasksSelected && ("external" as string) === 'ant' && coordinatorTaskCount > 0 && coordinatorTaskIndex > minCoordinatorIndex) { if (tasksSelected && (process.env.USER_TYPE) === 'ant' && coordinatorTaskCount > 0 && coordinatorTaskIndex > minCoordinatorIndex) {
setCoordinatorTaskIndex(prev => prev - 1); setCoordinatorTaskIndex(prev => prev - 1);
return; return;
} }
@ -1750,7 +1750,7 @@ function PromptInput({
}, },
'footer:down': () => { 'footer:down': () => {
// ↓ scrolls within the coordinator task list, never leaves the pill // ↓ scrolls within the coordinator task list, never leaves the pill
if (tasksSelected && ("external" as string) === 'ant' && coordinatorTaskCount > 0) { if (tasksSelected && (process.env.USER_TYPE) === 'ant' && coordinatorTaskCount > 0) {
if (coordinatorTaskIndex < coordinatorTaskCount - 1) { if (coordinatorTaskIndex < coordinatorTaskCount - 1) {
setCoordinatorTaskIndex(prev => prev + 1); setCoordinatorTaskIndex(prev => prev + 1);
} }
@ -1813,7 +1813,7 @@ function PromptInput({
} }
break; break;
case 'tmux': case 'tmux':
if (("external" as string) === 'ant') { if ((process.env.USER_TYPE) === 'ant') {
setAppState(prev => prev.tungstenPanelAutoHidden ? { setAppState(prev => prev.tungstenPanelAutoHidden ? {
...prev, ...prev,
tungstenPanelAutoHidden: false tungstenPanelAutoHidden: false

View File

@ -143,11 +143,11 @@ function PromptInputFooter({
</Box> </Box>
<Box flexShrink={1} gap={1}> <Box flexShrink={1} gap={1}>
{isFullscreen ? null : <Notifications apiKeyStatus={apiKeyStatus} autoUpdaterResult={autoUpdaterResult} debug={debug} isAutoUpdating={isAutoUpdating} verbose={verbose} messages={messages} onAutoUpdaterResult={onAutoUpdaterResult} onChangeIsUpdating={onChangeIsUpdating} ideSelection={ideSelection} mcpClients={mcpClients} isInputWrapped={isInputWrapped} isNarrow={isNarrow} />} {isFullscreen ? null : <Notifications apiKeyStatus={apiKeyStatus} autoUpdaterResult={autoUpdaterResult} debug={debug} isAutoUpdating={isAutoUpdating} verbose={verbose} messages={messages} onAutoUpdaterResult={onAutoUpdaterResult} onChangeIsUpdating={onChangeIsUpdating} ideSelection={ideSelection} mcpClients={mcpClients} isInputWrapped={isInputWrapped} isNarrow={isNarrow} />}
{("external" as string) === 'ant' && isUndercover() && <Text dimColor>undercover</Text>} {(process.env.USER_TYPE) === 'ant' && isUndercover() && <Text dimColor>undercover</Text>}
<BridgeStatusIndicator bridgeSelected={bridgeSelected} /> <BridgeStatusIndicator bridgeSelected={bridgeSelected} />
</Box> </Box>
</Box> </Box>
{("external" as string) === 'ant' && <CoordinatorTaskPanel />} {(process.env.USER_TYPE) === 'ant' && <CoordinatorTaskPanel />}
</>; </>;
} }
export default memo(PromptInputFooter); export default memo(PromptInputFooter);

View File

@ -260,7 +260,7 @@ function ModeIndicator({
const expandedView = useAppState(s_3 => s_3.expandedView); const expandedView = useAppState(s_3 => s_3.expandedView);
const showSpinnerTree = expandedView === 'teammates'; const showSpinnerTree = expandedView === 'teammates';
const prStatus = usePrStatus(isLoading, isPrStatusEnabled()); const prStatus = usePrStatus(isLoading, isPrStatusEnabled());
const hasTmuxSession = useAppState(s_4 => ("external" as string) === 'ant' && s_4.tungstenActiveSession !== undefined); const hasTmuxSession = useAppState(s_4 => (process.env.USER_TYPE) === 'ant' && s_4.tungstenActiveSession !== undefined);
const nextTickAt = useSyncExternalStore(proactiveModule?.subscribeToProactiveChanges ?? NO_OP_SUBSCRIBE, proactiveModule?.getNextTickAt ?? NULL, NULL); const nextTickAt = useSyncExternalStore(proactiveModule?.subscribeToProactiveChanges ?? NO_OP_SUBSCRIBE, proactiveModule?.getNextTickAt ?? NULL, NULL);
// biome-ignore lint/correctness/useHookAtTopLevel: feature() is a compile-time constant // biome-ignore lint/correctness/useHookAtTopLevel: feature() is a compile-time constant
const voiceEnabled = feature('VOICE_MODE') ? useVoiceEnabled() : false; const voiceEnabled = feature('VOICE_MODE') ? useVoiceEnabled() : false;
@ -274,7 +274,7 @@ function ModeIndicator({
const selGetState = useSelection().getState; const selGetState = useSelection().getState;
const hasNextTick = nextTickAt !== null; const hasNextTick = nextTickAt !== null;
const isCoordinator = feature('COORDINATOR_MODE') ? coordinatorModule?.isCoordinatorMode() === true : false; const isCoordinator = feature('COORDINATOR_MODE') ? coordinatorModule?.isCoordinatorMode() === true : false;
const runningTaskCount = useMemo(() => count(Object.values(tasks), t => isBackgroundTask(t) && !(("external" as string) === 'ant' && isPanelAgentTask(t))), [tasks]); const runningTaskCount = useMemo(() => count(Object.values(tasks), t => isBackgroundTask(t) && !((process.env.USER_TYPE) === 'ant' && isPanelAgentTask(t))), [tasks]);
const tasksV2 = useTasksV2(); const tasksV2 = useTasksV2();
const hasTaskItems = tasksV2 !== undefined && tasksV2.length > 0; const hasTaskItems = tasksV2 !== undefined && tasksV2.length > 0;
const escShortcut = useShortcutDisplay('chat:cancel', 'Chat', 'esc').toLowerCase(); const escShortcut = useShortcutDisplay('chat:cancel', 'Chat', 'esc').toLowerCase();
@ -365,7 +365,7 @@ function ModeIndicator({
// its click-target Box isn't nested inside the <Text wrap="truncate"> // its click-target Box isn't nested inside the <Text wrap="truncate">
// wrapper (reconciler throws on Box-in-Text). // wrapper (reconciler throws on Box-in-Text).
// Tmux pill (ant-only) — appears right after tasks in nav order // Tmux pill (ant-only) — appears right after tasks in nav order
...(("external" as string) === 'ant' && hasTmuxSession ? [<TungstenPill key="tmux" selected={tmuxSelected} />] : []), ...(isAgentSwarmsEnabled() && hasTeams ? [<TeamStatus key="teams" teamsSelected={teamsSelected} showHint={showHint && !hasBackgroundTasks} />] : []), ...(shouldShowPrStatus ? [<PrBadge key="pr-status" number={prStatus.number!} url={prStatus.url!} reviewState={prStatus.reviewState!} />] : [])]; ...((process.env.USER_TYPE) === 'ant' && hasTmuxSession ? [<TungstenPill key="tmux" selected={tmuxSelected} />] : []), ...(isAgentSwarmsEnabled() && hasTeams ? [<TeamStatus key="teams" teamsSelected={teamsSelected} showHint={showHint && !hasBackgroundTasks} />] : []), ...(shouldShowPrStatus ? [<PrBadge key="pr-status" number={prStatus.number!} url={prStatus.url!} reviewState={prStatus.reviewState!} />] : [])];
// Check if any in-process teammates exist (for hint text cycling) // Check if any in-process teammates exist (for hint text cycling)
const hasAnyInProcessTeammates = Object.values(tasks).some(t_2 => t_2.type === 'in_process_teammate' && t_2.status === 'running'); const hasAnyInProcessTeammates = Object.values(tasks).some(t_2 => t_2.type === 'in_process_teammate' && t_2.status === 'running');
@ -399,7 +399,7 @@ function ModeIndicator({
} }
// Add "↓ to manage tasks" hint when panel has visible rows // Add "↓ to manage tasks" hint when panel has visible rows
const hasCoordinatorTasks = ("external" as string) === 'ant' && getVisibleAgentTasks(tasks).length > 0; const hasCoordinatorTasks = (process.env.USER_TYPE) === 'ant' && getVisibleAgentTasks(tasks).length > 0;
// Tasks pill renders as a Box sibling (not a parts entry) so its // Tasks pill renders as a Box sibling (not a parts entry) so its
// click-target Box isn't nested inside <Text wrap="truncate"> — the // click-target Box isn't nested inside <Text wrap="truncate"> — the

View File

@ -392,7 +392,7 @@ export function Config({
} }
}] : []), }] : []),
// Speculation toggle (ant-only) // Speculation toggle (ant-only)
...(("external" as string) === 'ant' ? [{ ...((process.env.USER_TYPE) === 'ant' ? [{
id: 'speculationEnabled', id: 'speculationEnabled',
label: 'Speculative execution', label: 'Speculative execution',
value: globalConfig.speculationEnabled ?? true, value: globalConfig.speculationEnabled ?? true,

View File

@ -220,7 +220,7 @@ function SpinnerWithVerbInner({
// doesn't trigger re-renders; we pick up updates on the parent's ~25x/turn // doesn't trigger re-renders; we pick up updates on the parent's ~25x/turn
// re-render cadence, same as the old ApiMetricsLine did. // re-render cadence, same as the old ApiMetricsLine did.
let ttftText: string | null = null; let ttftText: string | null = null;
if (("external" as string) === 'ant' && apiMetricsRef?.current && apiMetricsRef.current.length > 0) { if ((process.env.USER_TYPE) === 'ant' && apiMetricsRef?.current && apiMetricsRef.current.length > 0) {
ttftText = computeTtftText(apiMetricsRef.current); ttftText = computeTtftText(apiMetricsRef.current);
} }

View File

@ -512,7 +512,7 @@ function OverviewTab({
</Box> </Box>
{/* Speculation time saved (ant-only) */} {/* Speculation time saved (ant-only) */}
{("external" as string) === 'ant' && stats.totalSpeculationTimeSavedMs > 0 && <Box flexDirection="row" gap={4}> {(process.env.USER_TYPE) === 'ant' && stats.totalSpeculationTimeSavedMs > 0 && <Box flexDirection="row" gap={4}>
<Box flexDirection="column" width={28}> <Box flexDirection="column" width={28}>
<Text wrap="truncate"> <Text wrap="truncate">
Speculation saved:{' '} Speculation saved:{' '}
@ -1151,7 +1151,7 @@ function renderOverviewToAnsi(stats: ClaudeCodeStats): string[] {
lines.push(row('Active days', activeDaysVal, 'Peak hour', peakHourVal)); lines.push(row('Active days', activeDaysVal, 'Peak hour', peakHourVal));
// Speculation time saved (ant-only) // Speculation time saved (ant-only)
if (("external" as string) === 'ant' && stats.totalSpeculationTimeSavedMs > 0) { if ((process.env.USER_TYPE) === 'ant' && stats.totalSpeculationTimeSavedMs > 0) {
const label = 'Speculation saved:'.padEnd(COL1_LABEL_WIDTH); const label = 'Speculation saved:'.padEnd(COL1_LABEL_WIDTH);
lines.push(label + h(formatDuration(stats.totalSpeculationTimeSavedMs))); lines.push(label + h(formatDuration(stats.totalSpeculationTimeSavedMs)));
} }

View File

@ -58,7 +58,7 @@ function getToolBuckets(): ToolBuckets {
}, },
EXECUTION: { EXECUTION: {
name: 'Execution tools', name: 'Execution tools',
toolNames: new Set([BashTool.name, ("external" as string) === 'ant' ? TungstenTool.name : undefined].filter(n => n !== undefined)) toolNames: new Set([BashTool.name, (process.env.USER_TYPE) === 'ant' ? TungstenTool.name : undefined].filter(n => n !== undefined))
}, },
MCP: { MCP: {
name: 'MCP tools', name: 'MCP tools',

View File

@ -114,7 +114,7 @@ export function AttachmentMessage({
// names — shortId is undefined outside ant builds anyway. // names — shortId is undefined outside ant builds anyway.
const names = attachment.skills.map(s => s.shortId ? `${s.name} [${s.shortId}]` : s.name).join(', '); const names = attachment.skills.map(s => s.shortId ? `${s.name} [${s.shortId}]` : s.name).join(', ');
const firstId = attachment.skills[0]?.shortId; const firstId = attachment.skills[0]?.shortId;
const hint = ("external" as string) === 'ant' && !isDemoEnv && firstId ? ` · /skill-feedback ${firstId} 1=wrong 2=noisy 3=good [comment]` : ''; const hint = (process.env.USER_TYPE) === 'ant' && !isDemoEnv && firstId ? ` · /skill-feedback ${firstId} 1=wrong 2=noisy 3=good [comment]` : '';
return <Line> return <Line>
<Text bold>{attachment.skills.length}</Text> relevant{' '} <Text bold>{attachment.skills.length}</Text> relevant{' '}
{plural(attachment.skills.length, 'skill')}: {names} {plural(attachment.skills.length, 'skill')}: {names}

View File

@ -112,7 +112,7 @@ export function bashToolUseOptions({
// Skip when the editable prefix option is already shown — they serve the // Skip when the editable prefix option is already shown — they serve the
// same role and having two identical-looking "don't ask again" inputs is confusing. // same role and having two identical-looking "don't ask again" inputs is confusing.
const editablePrefixShown = options.some(o => o.value === 'yes-prefix-edited'); const editablePrefixShown = options.some(o => o.value === 'yes-prefix-edited');
if (("external" as string) === 'ant' && !editablePrefixShown && isClassifierPermissionsEnabled() && onClassifierDescriptionChange && !initialClassifierDescriptionEmpty && !descriptionAlreadyExists(classifierDescription ?? '', existingAllowDescriptions) && decisionReason?.type !== 'classifier') { if ((process.env.USER_TYPE) === 'ant' && !editablePrefixShown && isClassifierPermissionsEnabled() && onClassifierDescriptionChange && !initialClassifierDescriptionEmpty && !descriptionAlreadyExists(classifierDescription ?? '', existingAllowDescriptions) && decisionReason?.type !== 'classifier') {
options.push({ options.push({
type: 'input', type: 'input',
label: 'Yes, and don\u2019t ask again for', label: 'Yes, and don\u2019t ask again for',

View File

@ -96,7 +96,7 @@ export function shouldHideTasksFooter(tasks: {
if (!showSpinnerTree) return false; if (!showSpinnerTree) return false;
let hasVisibleTask = false; let hasVisibleTask = false;
for (const t of Object.values(tasks) as TaskState[]) { for (const t of Object.values(tasks) as TaskState[]) {
if (!isBackgroundTask(t) || ("external" as string) === 'ant' && isPanelAgentTask(t)) { if (!isBackgroundTask(t) || (process.env.USER_TYPE) === 'ant' && isPanelAgentTask(t)) {
continue; continue;
} }
hasVisibleTask = true; hasVisibleTask = true;

View File

@ -262,13 +262,10 @@ function isBeingDebugged() {
} }
} }
// Exit if we detect node debugging or inspection // Anti-debugging check disabled for local development
if (("external" as string) !== 'ant' && isBeingDebugged()) { // if ((process.env.USER_TYPE) !== 'ant' && isBeingDebugged()) {
// Use process.exit directly here since we're in the top-level code before imports // process.exit(1);
// and gracefulShutdown is not yet available // }
// eslint-disable-next-line custom-rules/no-top-level-side-effects
process.exit(1);
}
/** /**
* Per-session skill/plugin telemetry. Called from both the interactive path * Per-session skill/plugin telemetry. Called from both the interactive path
@ -337,7 +334,7 @@ function runMigrations(): void {
if (feature('TRANSCRIPT_CLASSIFIER')) { if (feature('TRANSCRIPT_CLASSIFIER')) {
resetAutoModeOptInForDefaultOffer(); resetAutoModeOptInForDefaultOffer();
} }
if (("external" as string) === 'ant') { if ((process.env.USER_TYPE) === 'ant') {
migrateFennecToOpus(); migrateFennecToOpus();
} }
saveGlobalConfig(prev => prev.migrationVersion === CURRENT_MIGRATION_VERSION ? prev : { saveGlobalConfig(prev => prev.migrationVersion === CURRENT_MIGRATION_VERSION ? prev : {
@ -425,7 +422,7 @@ export function startDeferredPrefetches(): void {
} }
// Event loop stall detector — logs when the main thread is blocked >500ms // Event loop stall detector — logs when the main thread is blocked >500ms
if (("external" as string) === 'ant') { if ((process.env.USER_TYPE) === 'ant') {
void import('./utils/eventLoopStallDetector.js').then(m => m.startEventLoopStallDetector()); void import('./utils/eventLoopStallDetector.js').then(m => m.startEventLoopStallDetector());
} }
} }
@ -1134,11 +1131,11 @@ async function run(): Promise<CommanderCommand> {
const disableSlashCommands = options.disableSlashCommands || false; const disableSlashCommands = options.disableSlashCommands || false;
// Extract tasks mode options (ant-only) // Extract tasks mode options (ant-only)
const tasksOption = ("external" as string) === 'ant' && (options as { const tasksOption = (process.env.USER_TYPE) === 'ant' && (options as {
tasks?: boolean | string; tasks?: boolean | string;
}).tasks; }).tasks;
const taskListId = tasksOption ? typeof tasksOption === 'string' ? tasksOption : DEFAULT_TASKS_MODE_TASK_LIST_ID : undefined; const taskListId = tasksOption ? typeof tasksOption === 'string' ? tasksOption : DEFAULT_TASKS_MODE_TASK_LIST_ID : undefined;
if (("external" as string) === 'ant' && taskListId) { if ((process.env.USER_TYPE) === 'ant' && taskListId) {
process.env.CLAUDE_CODE_TASK_LIST_ID = taskListId; process.env.CLAUDE_CODE_TASK_LIST_ID = taskListId;
} }
@ -1528,7 +1525,7 @@ async function run(): Promise<CommanderCommand> {
}; };
// Store the explicit CLI flag so teammates can inherit it // Store the explicit CLI flag so teammates can inherit it
setChromeFlagOverride(chromeOpts.chrome); setChromeFlagOverride(chromeOpts.chrome);
const enableClaudeInChrome = shouldEnableClaudeInChrome(chromeOpts.chrome) && (("external" as string) === 'ant' || isClaudeAISubscriber()); const enableClaudeInChrome = shouldEnableClaudeInChrome(chromeOpts.chrome) && ((process.env.USER_TYPE) === 'ant' || isClaudeAISubscriber());
const autoEnableClaudeInChrome = !enableClaudeInChrome && shouldAutoEnableClaudeInChrome(); const autoEnableClaudeInChrome = !enableClaudeInChrome && shouldAutoEnableClaudeInChrome();
if (enableClaudeInChrome) { if (enableClaudeInChrome) {
const platform = getPlatform(); const platform = getPlatform();
@ -1760,7 +1757,7 @@ async function run(): Promise<CommanderCommand> {
} = initResult; } = initResult;
// Handle overly broad shell allow rules for ant users (Bash(*), PowerShell(*)) // Handle overly broad shell allow rules for ant users (Bash(*), PowerShell(*))
if (("external" as string) === 'ant' && overlyBroadBashPermissions.length > 0) { if ((process.env.USER_TYPE) === 'ant' && overlyBroadBashPermissions.length > 0) {
for (const permission of overlyBroadBashPermissions) { for (const permission of overlyBroadBashPermissions) {
logForDebugging(`Ignoring overly broad shell permission ${permission.ruleDisplay} from ${permission.sourceDisplay}`); logForDebugging(`Ignoring overly broad shell permission ${permission.ruleDisplay} from ${permission.sourceDisplay}`);
} }
@ -2010,7 +2007,7 @@ async function run(): Promise<CommanderCommand> {
// - no env override (which short-circuits _CACHED_MAY_BE_STALE before disk) // - no env override (which short-circuits _CACHED_MAY_BE_STALE before disk)
// - flag absent from disk (== null also catches pre-#22279 poisoned null) // - flag absent from disk (== null also catches pre-#22279 poisoned null)
const explicitModel = options.model || process.env.ANTHROPIC_MODEL; const explicitModel = options.model || process.env.ANTHROPIC_MODEL;
if (("external" as string) === 'ant' && explicitModel && explicitModel !== 'default' && !hasGrowthBookEnvOverride('tengu_ant_model_override') && getGlobalConfig().cachedGrowthBookFeatures?.['tengu_ant_model_override'] == null) { if ((process.env.USER_TYPE) === 'ant' && explicitModel && explicitModel !== 'default' && !hasGrowthBookEnvOverride('tengu_ant_model_override') && getGlobalConfig().cachedGrowthBookFeatures?.['tengu_ant_model_override'] == null) {
await initializeGrowthBook(); await initializeGrowthBook();
} }
@ -2156,7 +2153,7 @@ async function run(): Promise<CommanderCommand> {
// Log agent memory loaded event for tmux teammates // Log agent memory loaded event for tmux teammates
if (customAgent.memory) { if (customAgent.memory) {
logEvent('tengu_agent_memory_loaded', { logEvent('tengu_agent_memory_loaded', {
...(("external" as string) === 'ant' && { ...((process.env.USER_TYPE) === 'ant' && {
agent_type: customAgent.agentType as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS agent_type: customAgent.agentType as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS
}), }),
scope: customAgent.memory as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, scope: customAgent.memory as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
@ -2220,7 +2217,7 @@ async function run(): Promise<CommanderCommand> {
getFpsMetrics = ctx.getFpsMetrics; getFpsMetrics = ctx.getFpsMetrics;
stats = ctx.stats; stats = ctx.stats;
// Install asciicast recorder before Ink mounts (ant-only, opt-in via CLAUDE_CODE_TERMINAL_RECORDING=1) // Install asciicast recorder before Ink mounts (ant-only, opt-in via CLAUDE_CODE_TERMINAL_RECORDING=1)
if (("external" as string) === 'ant') { if ((process.env.USER_TYPE) === 'ant') {
installAsciicastRecorder(); installAsciicastRecorder();
} }
const { const {
@ -2816,7 +2813,7 @@ async function run(): Promise<CommanderCommand> {
if (!isBareMode()) { if (!isBareMode()) {
startDeferredPrefetches(); startDeferredPrefetches();
void import('./utils/backgroundHousekeeping.js').then(m => m.startBackgroundHousekeeping()); void import('./utils/backgroundHousekeeping.js').then(m => m.startBackgroundHousekeeping());
if (("external" as string) === 'ant') { if ((process.env.USER_TYPE) === 'ant') {
void import('./utils/sdkHeapDumpMonitor.js').then(m => m.startSdkMemoryMonitor()); void import('./utils/sdkHeapDumpMonitor.js').then(m => m.startSdkMemoryMonitor());
} }
} }
@ -3061,7 +3058,7 @@ async function run(): Promise<CommanderCommand> {
// - Runtime: uploader checks github.com/anthropics/* remote + gcloud auth. // - Runtime: uploader checks github.com/anthropics/* remote + gcloud auth.
// - Safety: CLAUDE_CODE_DISABLE_SESSION_DATA_UPLOAD=1 bypasses (tests set this). // - Safety: CLAUDE_CODE_DISABLE_SESSION_DATA_UPLOAD=1 bypasses (tests set this).
// Import is dynamic + async to avoid adding startup latency. // Import is dynamic + async to avoid adding startup latency.
const sessionUploaderPromise = ("external" as string) === 'ant' ? import('./utils/sessionDataUploader.js') : null; const sessionUploaderPromise = (process.env.USER_TYPE) === 'ant' ? import('./utils/sessionDataUploader.js') : null;
// Defer session uploader resolution to the onTurnComplete callback to avoid // Defer session uploader resolution to the onTurnComplete callback to avoid
// adding a new top-level await in main.tsx (performance-critical path). // adding a new top-level await in main.tsx (performance-critical path).
@ -3578,7 +3575,7 @@ async function run(): Promise<CommanderCommand> {
} }
} }
} }
if (("external" as string) === 'ant') { if ((process.env.USER_TYPE) === 'ant') {
if (options.resume && typeof options.resume === 'string' && !maybeSessionId) { if (options.resume && typeof options.resume === 'string' && !maybeSessionId) {
// Check for ccshare URL (e.g. https://go/ccshare/boris-20260311-211036) // Check for ccshare URL (e.g. https://go/ccshare/boris-20260311-211036)
const { const {
@ -3813,7 +3810,7 @@ async function run(): Promise<CommanderCommand> {
if (canUserConfigureAdvisor()) { if (canUserConfigureAdvisor()) {
program.addOption(new Option('--advisor <model>', 'Enable the server-side advisor tool with the specified model (alias or full ID).').hideHelp()); program.addOption(new Option('--advisor <model>', 'Enable the server-side advisor tool with the specified model (alias or full ID).').hideHelp());
} }
if (("external" as string) === 'ant') { if ((process.env.USER_TYPE) === 'ant') {
program.addOption(new Option('--delegate-permissions', '[ANT-ONLY] Alias for --permission-mode auto.').implies({ program.addOption(new Option('--delegate-permissions', '[ANT-ONLY] Alias for --permission-mode auto.').implies({
permissionMode: 'auto' permissionMode: 'auto'
})); }));
@ -4367,7 +4364,7 @@ async function run(): Promise<CommanderCommand> {
}); });
// claude up — run the project's CLAUDE.md "# claude up" setup instructions. // claude up — run the project's CLAUDE.md "# claude up" setup instructions.
if (("external" as string) === 'ant') { if ((process.env.USER_TYPE) === 'ant') {
program.command('up').description('[ANT-ONLY] Initialize or upgrade the local dev environment using the "# claude up" section of the nearest CLAUDE.md').action(async () => { program.command('up').description('[ANT-ONLY] Initialize or upgrade the local dev environment using the "# claude up" section of the nearest CLAUDE.md').action(async () => {
const { const {
up up
@ -4378,7 +4375,7 @@ async function run(): Promise<CommanderCommand> {
// claude rollback (ant-only) // claude rollback (ant-only)
// Rolls back to previous releases // Rolls back to previous releases
if (("external" as string) === 'ant') { if ((process.env.USER_TYPE) === 'ant') {
program.command('rollback [target]').description('[ANT-ONLY] Roll back to a previous release\n\nExamples:\n claude rollback Go 1 version back from current\n claude rollback 3 Go 3 versions back from current\n claude rollback 2.0.73-dev.20251217.t190658 Roll back to a specific version').option('-l, --list', 'List recent published versions with ages').option('--dry-run', 'Show what would be installed without installing').option('--safe', 'Roll back to the server-pinned safe version (set by oncall during incidents)').action(async (target?: string, options?: { program.command('rollback [target]').description('[ANT-ONLY] Roll back to a previous release\n\nExamples:\n claude rollback Go 1 version back from current\n claude rollback 3 Go 3 versions back from current\n claude rollback 2.0.73-dev.20251217.t190658 Roll back to a specific version').option('-l, --list', 'List recent published versions with ages').option('--dry-run', 'Show what would be installed without installing').option('--safe', 'Roll back to the server-pinned safe version (set by oncall during incidents)').action(async (target?: string, options?: {
list?: boolean; list?: boolean;
dryRun?: boolean; dryRun?: boolean;
@ -4402,7 +4399,7 @@ async function run(): Promise<CommanderCommand> {
}); });
// ant-only commands // ant-only commands
if (("external" as string) === 'ant') { if ((process.env.USER_TYPE) === 'ant') {
const validateLogId = (value: string) => { const validateLogId = (value: string) => {
const maybeSessionId = validateUuid(value); const maybeSessionId = validateUuid(value);
if (maybeSessionId) return maybeSessionId; if (maybeSessionId) return maybeSessionId;
@ -4436,7 +4433,7 @@ Examples:
} = await import('./cli/handlers/ant.js'); } = await import('./cli/handlers/ant.js');
await exportHandler(source, outputFile); await exportHandler(source, outputFile);
}); });
if (("external" as string) === 'ant') { if ((process.env.USER_TYPE) === 'ant') {
const taskCmd = program.command('task').description('[ANT-ONLY] Manage task list tasks'); const taskCmd = program.command('task').description('[ANT-ONLY] Manage task list tasks');
taskCmd.command('create <subject>').description('Create a new task').option('-d, --description <text>', 'Task description').option('-l, --list <id>', 'Task list ID (defaults to "tasklist")').action(async (subject: string, opts: { taskCmd.command('create <subject>').description('Create a new task').option('-d, --description <text>', 'Task description').option('-l, --list <id>', 'Task list ID (defaults to "tasklist")').action(async (subject: string, opts: {
description?: string; description?: string;
@ -4595,7 +4592,7 @@ async function logTenguInit({
assistantActivationPath: assistantActivationPath as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS assistantActivationPath: assistantActivationPath as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS
}), }),
autoUpdatesChannel: (getInitialSettings().autoUpdatesChannel ?? 'latest') as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, autoUpdatesChannel: (getInitialSettings().autoUpdatesChannel ?? 'latest') as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
...(("external" as string) === 'ant' ? (() => { ...((process.env.USER_TYPE) === 'ant' ? (() => {
const cwd = getCwd(); const cwd = getCwd();
const gitRoot = findGitRoot(cwd); const gitRoot = findGitRoot(cwd);
const rp = gitRoot ? relative(gitRoot, cwd) || '.' : undefined; const rp = gitRoot ? relative(gitRoot, cwd) || '.' : undefined;

View File

@ -104,13 +104,13 @@ const VoiceKeybindingHandler: typeof import('../hooks/useVoiceIntegration.js').V
// Frustration detection is ant-only (dogfooding). Conditional require so external // Frustration detection is ant-only (dogfooding). Conditional require so external
// builds eliminate the module entirely (including its two O(n) useMemos that run // builds eliminate the module entirely (including its two O(n) useMemos that run
// on every messages change, plus the GrowthBook fetch). // on every messages change, plus the GrowthBook fetch).
const useFrustrationDetection: typeof import('../components/FeedbackSurvey/useFrustrationDetection.js').useFrustrationDetection = ("external" as string) === 'ant' ? require('../components/FeedbackSurvey/useFrustrationDetection.js').useFrustrationDetection : () => ({ const useFrustrationDetection: typeof import('../components/FeedbackSurvey/useFrustrationDetection.js').useFrustrationDetection = (process.env.USER_TYPE) === 'ant' ? require('../components/FeedbackSurvey/useFrustrationDetection.js').useFrustrationDetection : () => ({
state: 'closed', state: 'closed',
handleTranscriptSelect: () => {} handleTranscriptSelect: () => {}
}); });
// Ant-only org warning. Conditional require so the org UUID list is // Ant-only org warning. Conditional require so the org UUID list is
// eliminated from external builds (one UUID is on excluded-strings). // eliminated from external builds (one UUID is on excluded-strings).
const useAntOrgWarningNotification: typeof import('../hooks/notifs/useAntOrgWarningNotification.js').useAntOrgWarningNotification = ("external" as string) === 'ant' ? require('../hooks/notifs/useAntOrgWarningNotification.js').useAntOrgWarningNotification : () => {}; const useAntOrgWarningNotification: typeof import('../hooks/notifs/useAntOrgWarningNotification.js').useAntOrgWarningNotification = (process.env.USER_TYPE) === 'ant' ? require('../hooks/notifs/useAntOrgWarningNotification.js').useAntOrgWarningNotification : () => {};
// Dead code elimination: conditional import for coordinator mode // Dead code elimination: conditional import for coordinator mode
const getCoordinatorUserContext: (mcpClients: ReadonlyArray<{ const getCoordinatorUserContext: (mcpClients: ReadonlyArray<{
name: string; name: string;
@ -219,9 +219,9 @@ import { EffortCallout, shouldShowEffortCallout } from '../components/EffortCall
import type { EffortValue } from '../utils/effort.js'; import type { EffortValue } from '../utils/effort.js';
import { RemoteCallout } from '../components/RemoteCallout.js'; import { RemoteCallout } from '../components/RemoteCallout.js';
/* eslint-disable custom-rules/no-process-env-top-level, @typescript-eslint/no-require-imports */ /* eslint-disable custom-rules/no-process-env-top-level, @typescript-eslint/no-require-imports */
const AntModelSwitchCallout = ("external" as string) === 'ant' ? require('../components/AntModelSwitchCallout.js').AntModelSwitchCallout : null; const AntModelSwitchCallout = (process.env.USER_TYPE) === 'ant' ? require('../components/AntModelSwitchCallout.js').AntModelSwitchCallout : null;
const shouldShowAntModelSwitch = ("external" as string) === 'ant' ? require('../components/AntModelSwitchCallout.js').shouldShowModelSwitchCallout : (): boolean => false; const shouldShowAntModelSwitch = (process.env.USER_TYPE) === 'ant' ? require('../components/AntModelSwitchCallout.js').shouldShowModelSwitchCallout : (): boolean => false;
const UndercoverAutoCallout = ("external" as string) === 'ant' ? require('../components/UndercoverAutoCallout.js').UndercoverAutoCallout : null; const UndercoverAutoCallout = (process.env.USER_TYPE) === 'ant' ? require('../components/UndercoverAutoCallout.js').UndercoverAutoCallout : null;
/* eslint-enable custom-rules/no-process-env-top-level, @typescript-eslint/no-require-imports */ /* eslint-enable custom-rules/no-process-env-top-level, @typescript-eslint/no-require-imports */
import { activityManager } from '../utils/activityManager.js'; import { activityManager } from '../utils/activityManager.js';
import { createAbortController } from '../utils/abortController.js'; import { createAbortController } from '../utils/abortController.js';
@ -602,7 +602,7 @@ export function REPL({
// Env-var gates hoisted to mount-time — isEnvTruthy does toLowerCase+trim+ // Env-var gates hoisted to mount-time — isEnvTruthy does toLowerCase+trim+
// includes, and these were on the render path (hot during PageUp spam). // includes, and these were on the render path (hot during PageUp spam).
const titleDisabled = useMemo(() => isEnvTruthy(process.env.CLAUDE_CODE_DISABLE_TERMINAL_TITLE), []); const titleDisabled = useMemo(() => isEnvTruthy(process.env.CLAUDE_CODE_DISABLE_TERMINAL_TITLE), []);
const moreRightEnabled = useMemo(() => ("external" as string) === 'ant' && isEnvTruthy(process.env.CLAUDE_MORERIGHT), []); const moreRightEnabled = useMemo(() => (process.env.USER_TYPE) === 'ant' && isEnvTruthy(process.env.CLAUDE_MORERIGHT), []);
const disableVirtualScroll = useMemo(() => isEnvTruthy(process.env.CLAUDE_CODE_DISABLE_VIRTUAL_SCROLL), []); const disableVirtualScroll = useMemo(() => isEnvTruthy(process.env.CLAUDE_CODE_DISABLE_VIRTUAL_SCROLL), []);
const disableMessageActions = feature('MESSAGE_ACTIONS') ? const disableMessageActions = feature('MESSAGE_ACTIONS') ?
// biome-ignore lint/correctness/useHookAtTopLevel: feature() is a compile-time constant // biome-ignore lint/correctness/useHookAtTopLevel: feature() is a compile-time constant
@ -734,7 +734,7 @@ export function REPL({
const [showIdeOnboarding, setShowIdeOnboarding] = useState(false); const [showIdeOnboarding, setShowIdeOnboarding] = useState(false);
// Dead code elimination: model switch callout state (ant-only) // Dead code elimination: model switch callout state (ant-only)
const [showModelSwitchCallout, setShowModelSwitchCallout] = useState(() => { const [showModelSwitchCallout, setShowModelSwitchCallout] = useState(() => {
if (("external" as string) === 'ant') { if ((process.env.USER_TYPE) === 'ant') {
return shouldShowAntModelSwitch(); return shouldShowAntModelSwitch();
} }
return false; return false;
@ -1013,7 +1013,7 @@ export function REPL({
}, []); }, []);
const [showUndercoverCallout, setShowUndercoverCallout] = useState(false); const [showUndercoverCallout, setShowUndercoverCallout] = useState(false);
useEffect(() => { useEffect(() => {
if (("external" as string) === 'ant') { if ((process.env.USER_TYPE) === 'ant') {
void (async () => { void (async () => {
// Wait for repo classification to settle (memoized, no-op if primed). // Wait for repo classification to settle (memoized, no-op if primed).
const { const {
@ -2045,10 +2045,10 @@ export function REPL({
if (allowDialogsWithAnimation && showIdeOnboarding) return 'ide-onboarding'; if (allowDialogsWithAnimation && showIdeOnboarding) return 'ide-onboarding';
// Model switch callout (ant-only, eliminated from external builds) // Model switch callout (ant-only, eliminated from external builds)
if (("external" as string) === 'ant' && allowDialogsWithAnimation && showModelSwitchCallout) return 'model-switch'; if ((process.env.USER_TYPE) === 'ant' && allowDialogsWithAnimation && showModelSwitchCallout) return 'model-switch';
// Undercover auto-enable explainer (ant-only, eliminated from external builds) // Undercover auto-enable explainer (ant-only, eliminated from external builds)
if (("external" as string) === 'ant' && allowDialogsWithAnimation && showUndercoverCallout) return 'undercover-callout'; if ((process.env.USER_TYPE) === 'ant' && allowDialogsWithAnimation && showUndercoverCallout) return 'undercover-callout';
// Effort callout (shown once for Opus 4.6 users when effort is enabled) // Effort callout (shown once for Opus 4.6 users when effort is enabled)
if (allowDialogsWithAnimation && showEffortCallout) return 'effort-callout'; if (allowDialogsWithAnimation && showEffortCallout) return 'effort-callout';
@ -2486,7 +2486,7 @@ export function REPL({
dynamicSkillDirTriggers: new Set<string>(), dynamicSkillDirTriggers: new Set<string>(),
discoveredSkillNames: discoveredSkillNamesRef.current, discoveredSkillNames: discoveredSkillNamesRef.current,
setResponseLength, setResponseLength,
pushApiMetricsEntry: ("external" as string) === 'ant' ? (ttftMs: number) => { pushApiMetricsEntry: (process.env.USER_TYPE) === 'ant' ? (ttftMs: number) => {
const now = Date.now(); const now = Date.now();
const baseline = responseLengthRef.current; const baseline = responseLengthRef.current;
apiMetricsRef.current.push({ apiMetricsRef.current.push({
@ -2815,7 +2815,7 @@ export function REPL({
// Capture ant-only API metrics before resetLoadingState clears the ref. // Capture ant-only API metrics before resetLoadingState clears the ref.
// For multi-request turns (tool use loops), compute P50 across all requests. // For multi-request turns (tool use loops), compute P50 across all requests.
if (("external" as string) === 'ant' && apiMetricsRef.current.length > 0) { if ((process.env.USER_TYPE) === 'ant' && apiMetricsRef.current.length > 0) {
const entries = apiMetricsRef.current; const entries = apiMetricsRef.current;
const ttfts = entries.map(e => e.ttftMs); const ttfts = entries.map(e => e.ttftMs);
// Compute per-request OTPS using only active streaming time and // Compute per-request OTPS using only active streaming time and
@ -2943,7 +2943,7 @@ export function REPL({
// minutes — wiping the session made the pill disappear entirely, forcing // minutes — wiping the session made the pill disappear entirely, forcing
// the user to re-invoke Tmux just to peek. Skip on abort so the panel // the user to re-invoke Tmux just to peek. Skip on abort so the panel
// stays open for inspection (matches the turn-duration guard below). // stays open for inspection (matches the turn-duration guard below).
if (("external" as string) === 'ant' && !abortController.signal.aborted) { if ((process.env.USER_TYPE) === 'ant' && !abortController.signal.aborted) {
setAppState(prev => { setAppState(prev => {
if (prev.tungstenActiveSession === undefined) return prev; if (prev.tungstenActiveSession === undefined) return prev;
if (prev.tungstenPanelAutoHidden === true) return prev; if (prev.tungstenPanelAutoHidden === true) return prev;
@ -3066,7 +3066,7 @@ export function REPL({
} }
// Atomically: clear initial message, set permission mode and rules, and store plan for verification // Atomically: clear initial message, set permission mode and rules, and store plan for verification
const shouldStorePlanForVerification = initialMsg.message.planContent && ("external" as string) === 'ant' && isEnvTruthy(undefined); const shouldStorePlanForVerification = initialMsg.message.planContent && (process.env.USER_TYPE) === 'ant' && isEnvTruthy(undefined);
setAppState(prev => { setAppState(prev => {
// Build and apply permission updates (mode + allowedPrompts rules) // Build and apply permission updates (mode + allowedPrompts rules)
let updatedToolPermissionContext = initialMsg.mode ? applyPermissionUpdates(prev.toolPermissionContext, buildPermissionUpdates(initialMsg.mode, initialMsg.allowedPrompts)) : prev.toolPermissionContext; let updatedToolPermissionContext = initialMsg.mode ? applyPermissionUpdates(prev.toolPermissionContext, buildPermissionUpdates(initialMsg.mode, initialMsg.allowedPrompts)) : prev.toolPermissionContext;
@ -3599,7 +3599,7 @@ export function REPL({
// Handler for when user presses 1 on survey thanks screen to share details // Handler for when user presses 1 on survey thanks screen to share details
const handleSurveyRequestFeedback = useCallback(() => { const handleSurveyRequestFeedback = useCallback(() => {
const command = ("external" as string) === 'ant' ? '/issue' : '/feedback'; const command = (process.env.USER_TYPE) === 'ant' ? '/issue' : '/feedback';
onSubmit(command, { onSubmit(command, {
setCursorOffset: () => {}, setCursorOffset: () => {},
clearBuffer: () => {}, clearBuffer: () => {},
@ -4060,7 +4060,7 @@ export function REPL({
// - Workers receive permission responses via mailbox messages // - Workers receive permission responses via mailbox messages
// - Leaders receive permission requests via mailbox messages // - Leaders receive permission requests via mailbox messages
if (("external" as string) === 'ant') { if ((process.env.USER_TYPE) === 'ant') {
// Tasks mode: watch for tasks and auto-process them // Tasks mode: watch for tasks and auto-process them
// eslint-disable-next-line react-hooks/rules-of-hooks // eslint-disable-next-line react-hooks/rules-of-hooks
// biome-ignore lint/correctness/useHookAtTopLevel: conditional for dead code elimination in external builds // biome-ignore lint/correctness/useHookAtTopLevel: conditional for dead code elimination in external builds
@ -4169,7 +4169,7 @@ export function REPL({
// Fall back to default behavior // Fall back to default behavior
const hookType = currentHooks[0]?.data.hookEvent === 'SubagentStop' ? 'subagent stop' : 'stop'; const hookType = currentHooks[0]?.data.hookEvent === 'SubagentStop' ? 'subagent stop' : 'stop';
if (("external" as string) === 'ant') { if ((process.env.USER_TYPE) === 'ant') {
const cmd = currentHooks[completedCount]?.data.command; const cmd = currentHooks[completedCount]?.data.command;
const label = cmd ? ` '${truncateToWidth(cmd, 40)}'` : ''; const label = cmd ? ` '${truncateToWidth(cmd, 40)}'` : '';
return total === 1 ? `running ${hookType} hook${label}` : `running ${hookType} hook${label}\u2026 ${completedCount}/${total}`; return total === 1 ? `running ${hookType} hook${label}` : `running ${hookType} hook${label}\u2026 ${completedCount}/${total}`;
@ -4578,7 +4578,7 @@ export function REPL({
{toolJSX && !(toolJSX.isLocalJSXCommand && toolJSX.isImmediate) && !toolJsxCentered && <Box flexDirection="column" width="100%"> {toolJSX && !(toolJSX.isLocalJSXCommand && toolJSX.isImmediate) && !toolJsxCentered && <Box flexDirection="column" width="100%">
{toolJSX.jsx} {toolJSX.jsx}
</Box>} </Box>}
{("external" as string) === 'ant' && <TungstenLiveMonitor />} {(process.env.USER_TYPE) === 'ant' && <TungstenLiveMonitor />}
{feature('WEB_BROWSER_TOOL') ? WebBrowserPanelModule && <WebBrowserPanelModule.WebBrowserPanel /> : null} {feature('WEB_BROWSER_TOOL') ? WebBrowserPanelModule && <WebBrowserPanelModule.WebBrowserPanel /> : null}
<Box flexGrow={1} /> <Box flexGrow={1} />
{showSpinner && <SpinnerWithVerb mode={streamMode} spinnerTip={spinnerTip} responseLengthRef={responseLengthRef} apiMetricsRef={apiMetricsRef} overrideMessage={spinnerMessage} spinnerSuffix={stopHookSpinnerSuffix} verbose={verbose} loadingStartTimeRef={loadingStartTimeRef} totalPausedMsRef={totalPausedMsRef} pauseStartTimeRef={pauseStartTimeRef} overrideColor={spinnerColor} overrideShimmerColor={spinnerShimmerColor} hasActiveTools={inProgressToolUseIDs.size > 0} leaderIsIdle={!isLoading} />} {showSpinner && <SpinnerWithVerb mode={streamMode} spinnerTip={spinnerTip} responseLengthRef={responseLengthRef} apiMetricsRef={apiMetricsRef} overrideMessage={spinnerMessage} spinnerSuffix={stopHookSpinnerSuffix} verbose={verbose} loadingStartTimeRef={loadingStartTimeRef} totalPausedMsRef={totalPausedMsRef} pauseStartTimeRef={pauseStartTimeRef} overrideColor={spinnerColor} overrideShimmerColor={spinnerShimmerColor} hasActiveTools={inProgressToolUseIDs.size > 0} leaderIsIdle={!isLoading} />}
@ -4801,7 +4801,7 @@ export function REPL({
}); });
}} />} }} />}
{focusedInputDialog === 'ide-onboarding' && <IdeOnboardingDialog onDone={() => setShowIdeOnboarding(false)} installationStatus={ideInstallationStatus} />} {focusedInputDialog === 'ide-onboarding' && <IdeOnboardingDialog onDone={() => setShowIdeOnboarding(false)} installationStatus={ideInstallationStatus} />}
{("external" as string) === 'ant' && focusedInputDialog === 'model-switch' && AntModelSwitchCallout && <AntModelSwitchCallout onDone={(selection: string, modelAlias?: string) => { {(process.env.USER_TYPE) === 'ant' && focusedInputDialog === 'model-switch' && AntModelSwitchCallout && <AntModelSwitchCallout onDone={(selection: string, modelAlias?: string) => {
setShowModelSwitchCallout(false); setShowModelSwitchCallout(false);
if (selection === 'switch' && modelAlias) { if (selection === 'switch' && modelAlias) {
setAppState(prev => ({ setAppState(prev => ({
@ -4811,7 +4811,7 @@ export function REPL({
})); }));
} }
}} />} }} />}
{("external" as string) === 'ant' && focusedInputDialog === 'undercover-callout' && UndercoverAutoCallout && <UndercoverAutoCallout onDone={() => setShowUndercoverCallout(false)} />} {(process.env.USER_TYPE) === 'ant' && focusedInputDialog === 'undercover-callout' && UndercoverAutoCallout && <UndercoverAutoCallout onDone={() => setShowUndercoverCallout(false)} />}
{focusedInputDialog === 'effort-callout' && <EffortCallout model={mainLoopModel} onDone={selection => { {focusedInputDialog === 'effort-callout' && <EffortCallout model={mainLoopModel} onDone={selection => {
setShowEffortCallout(false); setShowEffortCallout(false);
if (selection !== 'dismiss') { if (selection !== 'dismiss') {
@ -4894,7 +4894,7 @@ export function REPL({
{/* Frustration-triggered transcript sharing prompt */} {/* Frustration-triggered transcript sharing prompt */}
{frustrationDetection.state !== 'closed' && <FeedbackSurvey state={frustrationDetection.state} lastResponse={null} handleSelect={() => {}} handleTranscriptSelect={frustrationDetection.handleTranscriptSelect} inputValue={inputValue} setInputValue={setInputValue} />} {frustrationDetection.state !== 'closed' && <FeedbackSurvey state={frustrationDetection.state} lastResponse={null} handleSelect={() => {}} handleTranscriptSelect={frustrationDetection.handleTranscriptSelect} inputValue={inputValue} setInputValue={setInputValue} />}
{/* Skill improvement survey - appears when improvements detected (ant-only) */} {/* Skill improvement survey - appears when improvements detected (ant-only) */}
{("external" as string) === 'ant' && skillImprovementSurvey.suggestion && <SkillImprovementSurvey isOpen={skillImprovementSurvey.isOpen} skillName={skillImprovementSurvey.suggestion.skillName} updates={skillImprovementSurvey.suggestion.updates} handleSelect={skillImprovementSurvey.handleSelect} inputValue={inputValue} setInputValue={setInputValue} />} {(process.env.USER_TYPE) === 'ant' && skillImprovementSurvey.suggestion && <SkillImprovementSurvey isOpen={skillImprovementSurvey.isOpen} skillName={skillImprovementSurvey.suggestion.skillName} updates={skillImprovementSurvey.suggestion.updates} handleSelect={skillImprovementSurvey.handleSelect} inputValue={inputValue} setInputValue={setInputValue} />}
{showIssueFlagBanner && <IssueFlagBanner />} {showIssueFlagBanner && <IssueFlagBanner />}
{} {}
<PromptInput debug={debug} ideSelection={ideSelection} hasSuppressedDialogs={!!hasSuppressedDialogs} isLocalJSXCommandActive={isShowingLocalJSXCommand} getToolUseContext={getToolUseContext} toolPermissionContext={toolPermissionContext} setToolPermissionContext={setToolPermissionContext} apiKeyStatus={apiKeyStatus} commands={commands} agents={agentDefinitions.activeAgents} isLoading={isLoading} onExit={handleExit} verbose={verbose} messages={messages} onAutoUpdaterResult={setAutoUpdaterResult} autoUpdaterResult={autoUpdaterResult} input={inputValue} onInputChange={setInputValue} mode={inputMode} onModeChange={setInputMode} stashedPrompt={stashedPrompt} setStashedPrompt={setStashedPrompt} submitCount={submitCount} onShowMessageSelector={handleShowMessageSelector} onMessageActionsEnter={ <PromptInput debug={debug} ideSelection={ideSelection} hasSuppressedDialogs={!!hasSuppressedDialogs} isLocalJSXCommandActive={isShowingLocalJSXCommand} getToolUseContext={getToolUseContext} toolPermissionContext={toolPermissionContext} setToolPermissionContext={setToolPermissionContext} apiKeyStatus={apiKeyStatus} commands={commands} agents={agentDefinitions.activeAgents} isLoading={isLoading} onExit={handleExit} verbose={verbose} messages={messages} onAutoUpdaterResult={setAutoUpdaterResult} autoUpdaterResult={autoUpdaterResult} input={inputValue} onInputChange={setInputValue} mode={inputMode} onModeChange={setInputMode} stashedPrompt={stashedPrompt} setStashedPrompt={setStashedPrompt} submitCount={submitCount} onShowMessageSelector={handleShowMessageSelector} onMessageActionsEnter={
@ -4987,7 +4987,7 @@ export function REPL({
setIsMessageSelectorVisible(false); setIsMessageSelectorVisible(false);
setMessageSelectorPreselect(undefined); setMessageSelectorPreselect(undefined);
}} />} }} />}
{("external" as string) === 'ant' && <DevBar />} {(process.env.USER_TYPE) === 'ant' && <DevBar />}
</Box> </Box>
{feature('BUDDY') && !(companionNarrow && isFullscreenEnvEnabled()) && companionVisible ? <CompanionSprite /> : null} {feature('BUDDY') && !(companionNarrow && isFullscreenEnvEnabled()) && companionVisible ? <CompanionSprite /> : null}
</Box>} /> </Box>} />

View File

@ -96,7 +96,7 @@ const fullInputSchema = lazySchema(() => {
mode: permissionModeSchema().optional().describe('Permission mode for spawned teammate (e.g., "plan" to require plan approval).') mode: permissionModeSchema().optional().describe('Permission mode for spawned teammate (e.g., "plan" to require plan approval).')
}); });
return baseInputSchema().merge(multiAgentInputSchema).extend({ return baseInputSchema().merge(multiAgentInputSchema).extend({
isolation: (("external" as string) === 'ant' ? z.enum(['worktree', 'remote']) : z.enum(['worktree'])).optional().describe(("external" as string) === 'ant' ? 'Isolation mode. "worktree" creates a temporary git worktree so the agent works on an isolated copy of the repo. "remote" launches the agent in a remote CCR environment (always runs in background).' : 'Isolation mode. "worktree" creates a temporary git worktree so the agent works on an isolated copy of the repo.'), isolation: ((process.env.USER_TYPE) === 'ant' ? z.enum(['worktree', 'remote']) : z.enum(['worktree'])).optional().describe((process.env.USER_TYPE) === 'ant' ? 'Isolation mode. "worktree" creates a temporary git worktree so the agent works on an isolated copy of the repo. "remote" launches the agent in a remote CCR environment (always runs in background).' : 'Isolation mode. "worktree" creates a temporary git worktree so the agent works on an isolated copy of the repo.'),
cwd: z.string().optional().describe('Absolute path to run the agent in. Overrides the working directory for all filesystem and shell operations within this agent. Mutually exclusive with isolation: "worktree".') cwd: z.string().optional().describe('Absolute path to run the agent in. Overrides the working directory for all filesystem and shell operations within this agent. Mutually exclusive with isolation: "worktree".')
}); });
}); });
@ -432,7 +432,7 @@ export const AgentTool = buildTool({
// Remote isolation: delegate to CCR. Gated ant-only — the guard enables // Remote isolation: delegate to CCR. Gated ant-only — the guard enables
// dead code elimination of the entire block for external builds. // dead code elimination of the entire block for external builds.
if (("external" as string) === 'ant' && effectiveIsolation === 'remote') { if ((process.env.USER_TYPE) === 'ant' && effectiveIsolation === 'remote') {
const eligibility = await checkRemoteAgentEligibility(); const eligibility = await checkRemoteAgentEligibility();
if (!eligibility.eligible) { if (!eligibility.eligible) {
const reasons = (eligibility as { eligible: false; errors: Parameters<typeof formatPreconditionError>[0][] }).errors.map(formatPreconditionError).join('\n'); const reasons = (eligibility as { eligible: false; errors: Parameters<typeof formatPreconditionError>[0][] }).errors.map(formatPreconditionError).join('\n');
@ -522,7 +522,7 @@ export const AgentTool = buildTool({
// Log agent memory loaded event for subagents // Log agent memory loaded event for subagents
if (selectedAgent.memory) { if (selectedAgent.memory) {
logEvent('tengu_agent_memory_loaded', { logEvent('tengu_agent_memory_loaded', {
...(("external" as string) === 'ant' && { ...((process.env.USER_TYPE) === 'ant' && {
agent_type: selectedAgent.agentType as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS agent_type: selectedAgent.agentType as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS
}), }),
scope: selectedAgent.memory as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, scope: selectedAgent.memory as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
@ -1284,7 +1284,7 @@ export const AgentTool = buildTool({
// Only route through auto mode classifier when in auto mode // Only route through auto mode classifier when in auto mode
// In all other modes, auto-approve sub-agent generation // In all other modes, auto-approve sub-agent generation
// Note: "external" === 'ant' guard enables dead code elimination for external builds // Note: "external" === 'ant' guard enables dead code elimination for external builds
if (("external" as string) === 'ant' && appState.toolPermissionContext.mode === 'auto') { if ((process.env.USER_TYPE) === 'ant' && appState.toolPermissionContext.mode === 'auto') {
return { return {
behavior: 'passthrough', behavior: 'passthrough',
message: 'Agent tool requires permission to spawn sub-agents.' message: 'Agent tool requires permission to spawn sub-agents.'

View File

@ -99,7 +99,7 @@ type ProcessedMessage = {
*/ */
function processProgressMessages(messages: ProgressMessage<Progress>[], tools: Tools, isAgentRunning: boolean): ProcessedMessage[] { function processProgressMessages(messages: ProgressMessage<Progress>[], tools: Tools, isAgentRunning: boolean): ProcessedMessage[] {
// Only process for ants // Only process for ants
if (("external" as string) !== 'ant') { if ((process.env.USER_TYPE) !== 'ant') {
return messages.filter((m): m is ProgressMessage<AgentToolProgress> => hasProgressMessage(m.data) && m.data.message.type !== 'user').map(m => ({ return messages.filter((m): m is ProgressMessage<AgentToolProgress> => hasProgressMessage(m.data) && m.data.message.type !== 'user').map(m => ({
type: 'original', type: 'original',
message: m message: m
@ -385,7 +385,7 @@ export function renderToolResultMessage(data: Output, progressMessagesForMessage
} as import('@anthropic-ai/sdk/resources/beta/messages/messages.mjs').BetaUsage } as import('@anthropic-ai/sdk/resources/beta/messages/messages.mjs').BetaUsage
}); });
return <Box flexDirection="column"> return <Box flexDirection="column">
{("external" as string) === 'ant' && <MessageResponse> {(process.env.USER_TYPE) === 'ant' && <MessageResponse>
<Text color="warning"> <Text color="warning">
[ANT-ONLY] API calls: {getDisplayPath(getDumpPromptsPath(agentId))} [ANT-ONLY] API calls: {getDisplayPath(getDumpPromptsPath(agentId))}
</Text> </Text>
@ -591,7 +591,7 @@ export function renderToolUseRejectedMessage(_input: {
const firstData = progressMessagesForMessage[0]?.data; const firstData = progressMessagesForMessage[0]?.data;
const agentId = firstData && hasProgressMessage(firstData) ? firstData.agentId : undefined; const agentId = firstData && hasProgressMessage(firstData) ? firstData.agentId : undefined;
return <> return <>
{("external" as string) === 'ant' && agentId && <MessageResponse> {(process.env.USER_TYPE) === 'ant' && agentId && <MessageResponse>
<Text color="warning"> <Text color="warning">
[ANT-ONLY] API calls: {getDisplayPath(getDumpPromptsPath(agentId))} [ANT-ONLY] API calls: {getDisplayPath(getDumpPromptsPath(agentId))}
</Text> </Text>

View File

@ -161,7 +161,7 @@ export const TaskOutputTool: Tool<InputSchema, TaskOutputToolOutput> = buildTool
return this.isReadOnly?.(_input) ?? false; return this.isReadOnly?.(_input) ?? false;
}, },
isEnabled() { isEnabled() {
return ("external" as string) !== 'ant'; return (process.env.USER_TYPE) !== 'ant';
}, },
isReadOnly(_input) { isReadOnly(_input) {
return true; return true;

View File

@ -25,7 +25,7 @@ export function renderToolResultMessage(output: Output, _progressMessagesForMess
}: { }: {
verbose: boolean; verbose: boolean;
}): React.ReactNode { }): React.ReactNode {
if (("external" as string) === 'ant') { if ((process.env.USER_TYPE) === 'ant') {
return null; return null;
} }
const rawCommand = output.command ?? ''; const rawCommand = output.command ?? '';

View File

@ -81,7 +81,7 @@ export type AutoRunIssueReason = 'feedback_survey_bad' | 'feedback_survey_good';
*/ */
export function shouldAutoRunIssue(reason: AutoRunIssueReason): boolean { export function shouldAutoRunIssue(reason: AutoRunIssueReason): boolean {
// Only for Ant users // Only for Ant users
if (("external" as string) !== 'ant') { if ((process.env.USER_TYPE) !== 'ant') {
return false; return false;
} }
switch (reason) { switch (reason) {
@ -100,7 +100,7 @@ export function shouldAutoRunIssue(reason: AutoRunIssueReason): boolean {
*/ */
export function getAutoRunCommand(reason: AutoRunIssueReason): string { export function getAutoRunCommand(reason: AutoRunIssueReason): string {
// Only ant builds have the /good-claude command // Only ant builds have the /good-claude command
if (("external" as string) === 'ant' && reason === 'feedback_survey_good') { if ((process.env.USER_TYPE) === 'ant' && reason === 'feedback_survey_good') {
return '/good-claude'; return '/good-claude';
} }
return '/issue'; return '/issue';

View File

@ -273,7 +273,7 @@ async function executeForkedSlashCommand(command: CommandBase & PromptCommand, a
logForDebugging(`Forked slash command /${command.name} completed with agent ${agentId}`); logForDebugging(`Forked slash command /${command.name} completed with agent ${agentId}`);
// Prepend debug log for ant users so it appears inside the command output // Prepend debug log for ant users so it appears inside the command output
if (("external" as string) === 'ant') { if ((process.env.USER_TYPE) === 'ant') {
resultText = `[ANT-ONLY] API calls: ${getDisplayPath(getDumpPromptsPath(agentId))}\n${resultText}`; resultText = `[ANT-ONLY] API calls: ${getDisplayPath(getDumpPromptsPath(agentId))}\n${resultText}`;
} }
@ -427,7 +427,7 @@ export async function processSlashCommand(inputString: string, precedingInputBlo
logEvent('tengu_input_command', { logEvent('tengu_input_command', {
...eventData, ...eventData,
invocation_trigger: 'user-slash' as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, invocation_trigger: 'user-slash' as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
...(("external" as string) === 'ant' && { ...((process.env.USER_TYPE) === 'ant' && {
skill_name: commandName as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, skill_name: commandName as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
...(returnedCommand.type === 'prompt' && { ...(returnedCommand.type === 'prompt' && {
skill_source: returnedCommand.source as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS skill_source: returnedCommand.source as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS
@ -495,7 +495,7 @@ export async function processSlashCommand(inputString: string, precedingInputBlo
logEvent('tengu_input_command', { logEvent('tengu_input_command', {
...eventData, ...eventData,
invocation_trigger: 'user-slash' as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, invocation_trigger: 'user-slash' as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
...(("external" as string) === 'ant' && { ...((process.env.USER_TYPE) === 'ant' && {
skill_name: commandName as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, skill_name: commandName as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
...(returnedCommand.type === 'prompt' && { ...(returnedCommand.type === 'prompt' && {
skill_source: returnedCommand.source as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS skill_source: returnedCommand.source as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS

View File

@ -26,7 +26,7 @@ export type Property = {
}; };
export type Diagnostic = React.ReactNode; export type Diagnostic = React.ReactNode;
export function buildSandboxProperties(): Property[] { export function buildSandboxProperties(): Property[] {
if (("external" as string) !== 'ant') { if ((process.env.USER_TYPE) !== 'ant') {
return []; return [];
} }
const isSandboxed = SandboxManager.isSandboxingEnabled(); const isSandboxed = SandboxManager.isSandboxingEnabled();