fix: 批量修正 external 字面量
This commit is contained in:
parent
799dacc407
commit
ac1f02958c
@ -10,12 +10,12 @@ import { getRainbowColor } from '../utils/thinking.js';
|
||||
// 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.
|
||||
export function isBuddyTeaserWindow(): boolean {
|
||||
if (("external" as string) === 'ant') return true;
|
||||
if ((process.env.USER_TYPE) === 'ant') return true;
|
||||
const d = new Date();
|
||||
return d.getFullYear() === 2026 && d.getMonth() === 3 && d.getDate() <= 7;
|
||||
}
|
||||
export function isBuddyLive(): boolean {
|
||||
if (("external" as string) === 'ant') return true;
|
||||
if ((process.env.USER_TYPE) === 'ant') return true;
|
||||
const d = new Date();
|
||||
return d.getFullYear() > 2026 || d.getFullYear() === 2026 && d.getMonth() >= 3;
|
||||
}
|
||||
|
||||
@ -77,7 +77,7 @@ export async function call(onDone: LocalJSXCommandOnDone, _context: unknown, arg
|
||||
}
|
||||
|
||||
// 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 <MCPSettings onComplete={onDone} />;
|
||||
|
||||
@ -119,7 +119,7 @@ export async function setupTerminal(theme: ThemeName): Promise<string> {
|
||||
maybeMarkProjectOnboardingComplete();
|
||||
|
||||
// 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);
|
||||
}
|
||||
return result;
|
||||
|
||||
@ -29,10 +29,10 @@ const INTERNAL_MARKETPLACE_NAME = 'claude-code-marketplace';
|
||||
const INTERNAL_MARKETPLACE_REPO = 'anthropics/claude-code-marketplace';
|
||||
const OFFICIAL_MARKETPLACE_REPO = 'anthropics/claude-plugins-official';
|
||||
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 {
|
||||
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 {
|
||||
return `thinkback@${getMarketplaceName()}`;
|
||||
|
||||
@ -53,7 +53,7 @@ const DEFAULT_INSTRUCTIONS: string = (typeof _rawPrompt === 'string' ? _rawPromp
|
||||
// Shell-set env only, so top-level process.env read is fine
|
||||
// — 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) */
|
||||
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 */
|
||||
|
||||
/**
|
||||
@ -464,7 +464,7 @@ export default {
|
||||
name: 'ultraplan',
|
||||
description: `~10–30 min · Claude Code on the web drafts an advanced plan you can edit and approve. See ${CCR_TERMS_URL}`,
|
||||
argumentHint: '<prompt>',
|
||||
isEnabled: () => ("external" as string) === 'ant',
|
||||
isEnabled: () => (process.env.USER_TYPE) === 'ant',
|
||||
load: () => Promise.resolve({
|
||||
call
|
||||
})
|
||||
|
||||
@ -6,7 +6,7 @@ import { Text, useInterval } from '../ink.js';
|
||||
|
||||
// Show DevBar for dev builds or all ants
|
||||
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() {
|
||||
const $ = _c(5);
|
||||
|
||||
@ -32,7 +32,7 @@ import TextInput from './TextInput.js';
|
||||
|
||||
// This value was determined experimentally by testing the URL length limit
|
||||
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 = {
|
||||
abortSignal: AbortSignal;
|
||||
messages: Message[];
|
||||
|
||||
@ -87,7 +87,7 @@ export function useMemorySurvey(messages: Message[], isLoading: boolean, hasActi
|
||||
});
|
||||
}, []);
|
||||
const shouldShowTranscriptPrompt = useCallback((selected_0: FeedbackSurveyResponse) => {
|
||||
if (("external" as string) !== 'ant') {
|
||||
if ((process.env.USER_TYPE) !== 'ant') {
|
||||
return false;
|
||||
}
|
||||
if (selected_0 !== 'bad' && selected_0 !== 'good') {
|
||||
|
||||
@ -26,7 +26,7 @@ export function createRecentActivityFeed(activities: LogOption[]): FeedConfig {
|
||||
}
|
||||
export function createWhatsNewFeed(releaseNotes: string[]): FeedConfig {
|
||||
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+(.+)$/);
|
||||
if (match) {
|
||||
return {
|
||||
@ -39,9 +39,9 @@ export function createWhatsNewFeed(releaseNotes: string[]): FeedConfig {
|
||||
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 {
|
||||
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,
|
||||
footer: lines.length > 0 ? '/release-notes for more' : undefined,
|
||||
emptyMessage
|
||||
|
||||
@ -7,7 +7,7 @@ export function MemoryUsageIndicator(): React.ReactNode {
|
||||
// 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
|
||||
// reached or dead-code-eliminated — never conditional at runtime.
|
||||
if (("external" as string) !== 'ant') {
|
||||
if ((process.env.USER_TYPE) !== 'ant') {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@ -118,7 +118,7 @@ export function MessageSelector({
|
||||
...summarizeInputProps,
|
||||
onChange: setSummarizeFromFeedback
|
||||
});
|
||||
if (("external" as string) === 'ant') {
|
||||
if ((process.env.USER_TYPE) === 'ant') {
|
||||
baseOptions.push({
|
||||
value: 'summarize_up_to',
|
||||
label: 'Summarize up to here',
|
||||
|
||||
@ -184,7 +184,7 @@ export function NativeAutoUpdater({
|
||||
{autoUpdaterResult?.status === 'install_failed' && <Text color="error" wrap="truncate">
|
||||
✗ Auto-update failed · Try <Text bold>/status</Text>
|
||||
</Text>}
|
||||
{maxVersionIssue && ("external" as string) === 'ant' && <Text color="warning">
|
||||
{maxVersionIssue && (process.env.USER_TYPE) === 'ant' && <Text color="warning">
|
||||
⚠ Known issue: {maxVersionIssue} · Run{' '}
|
||||
<Text bold>claude rollback --safe</Text> to downgrade
|
||||
</Text>}
|
||||
|
||||
@ -294,8 +294,8 @@ function PromptInput({
|
||||
// otherwise bridge becomes an invisible selection stop.
|
||||
const bridgeFooterVisible = replBridgeConnected && (replBridgeExplicit || replBridgeReconnecting);
|
||||
// Tmux pill (ant-only) — visible when there's an active tungsten session
|
||||
const hasTungstenSession = useAppState(s => ("external" as string) === 'ant' && s.tungstenActiveSession !== undefined);
|
||||
const tmuxFooterVisible = ("external" as string) === 'ant' && hasTungstenSession;
|
||||
const hasTungstenSession = useAppState(s => (process.env.USER_TYPE) === 'ant' && s.tungstenActiveSession !== undefined);
|
||||
const tmuxFooterVisible = (process.env.USER_TYPE) === 'ant' && hasTungstenSession;
|
||||
// WebBrowser pill — visible when a browser is open
|
||||
const bagelFooterVisible = useAppState(s => false);
|
||||
const teamContext = useAppState(s => s.teamContext);
|
||||
@ -391,7 +391,7 @@ function PromptInput({
|
||||
// exist. When only local_agent tasks are running (coordinator/fork mode), the
|
||||
// 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.
|
||||
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;
|
||||
// Clamp index when tasks complete and the list shrinks beneath the cursor
|
||||
useEffect(() => {
|
||||
@ -455,7 +455,7 @@ function PromptInput({
|
||||
// Panel shows retained-completed agents too (getVisibleAgentTasks), so the
|
||||
// pill must stay navigable whenever the panel has rows — not just when
|
||||
// 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 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({
|
||||
'footer:up': () => {
|
||||
// ↑ 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);
|
||||
return;
|
||||
}
|
||||
@ -1750,7 +1750,7 @@ function PromptInput({
|
||||
},
|
||||
'footer:down': () => {
|
||||
// ↓ 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) {
|
||||
setCoordinatorTaskIndex(prev => prev + 1);
|
||||
}
|
||||
@ -1813,7 +1813,7 @@ function PromptInput({
|
||||
}
|
||||
break;
|
||||
case 'tmux':
|
||||
if (("external" as string) === 'ant') {
|
||||
if ((process.env.USER_TYPE) === 'ant') {
|
||||
setAppState(prev => prev.tungstenPanelAutoHidden ? {
|
||||
...prev,
|
||||
tungstenPanelAutoHidden: false
|
||||
|
||||
@ -143,11 +143,11 @@ function PromptInputFooter({
|
||||
</Box>
|
||||
<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} />}
|
||||
{("external" as string) === 'ant' && isUndercover() && <Text dimColor>undercover</Text>}
|
||||
{(process.env.USER_TYPE) === 'ant' && isUndercover() && <Text dimColor>undercover</Text>}
|
||||
<BridgeStatusIndicator bridgeSelected={bridgeSelected} />
|
||||
</Box>
|
||||
</Box>
|
||||
{("external" as string) === 'ant' && <CoordinatorTaskPanel />}
|
||||
{(process.env.USER_TYPE) === 'ant' && <CoordinatorTaskPanel />}
|
||||
</>;
|
||||
}
|
||||
export default memo(PromptInputFooter);
|
||||
|
||||
@ -260,7 +260,7 @@ function ModeIndicator({
|
||||
const expandedView = useAppState(s_3 => s_3.expandedView);
|
||||
const showSpinnerTree = expandedView === 'teammates';
|
||||
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);
|
||||
// biome-ignore lint/correctness/useHookAtTopLevel: feature() is a compile-time constant
|
||||
const voiceEnabled = feature('VOICE_MODE') ? useVoiceEnabled() : false;
|
||||
@ -274,7 +274,7 @@ function ModeIndicator({
|
||||
const selGetState = useSelection().getState;
|
||||
const hasNextTick = nextTickAt !== null;
|
||||
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 hasTaskItems = tasksV2 !== undefined && tasksV2.length > 0;
|
||||
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">
|
||||
// wrapper (reconciler throws on Box-in-Text).
|
||||
// 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)
|
||||
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
|
||||
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
|
||||
// click-target Box isn't nested inside <Text wrap="truncate"> — the
|
||||
|
||||
@ -392,7 +392,7 @@ export function Config({
|
||||
}
|
||||
}] : []),
|
||||
// Speculation toggle (ant-only)
|
||||
...(("external" as string) === 'ant' ? [{
|
||||
...((process.env.USER_TYPE) === 'ant' ? [{
|
||||
id: 'speculationEnabled',
|
||||
label: 'Speculative execution',
|
||||
value: globalConfig.speculationEnabled ?? true,
|
||||
|
||||
@ -220,7 +220,7 @@ function SpinnerWithVerbInner({
|
||||
// doesn't trigger re-renders; we pick up updates on the parent's ~25x/turn
|
||||
// re-render cadence, same as the old ApiMetricsLine did.
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@ -512,7 +512,7 @@ function OverviewTab({
|
||||
</Box>
|
||||
|
||||
{/* 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}>
|
||||
<Text wrap="truncate">
|
||||
Speculation saved:{' '}
|
||||
@ -1151,7 +1151,7 @@ function renderOverviewToAnsi(stats: ClaudeCodeStats): string[] {
|
||||
lines.push(row('Active days', activeDaysVal, 'Peak hour', peakHourVal));
|
||||
|
||||
// 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);
|
||||
lines.push(label + h(formatDuration(stats.totalSpeculationTimeSavedMs)));
|
||||
}
|
||||
|
||||
@ -58,7 +58,7 @@ function getToolBuckets(): ToolBuckets {
|
||||
},
|
||||
EXECUTION: {
|
||||
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: {
|
||||
name: 'MCP tools',
|
||||
|
||||
@ -114,7 +114,7 @@ export function AttachmentMessage({
|
||||
// names — shortId is undefined outside ant builds anyway.
|
||||
const names = attachment.skills.map(s => s.shortId ? `${s.name} [${s.shortId}]` : s.name).join(', ');
|
||||
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>
|
||||
<Text bold>{attachment.skills.length}</Text> relevant{' '}
|
||||
{plural(attachment.skills.length, 'skill')}: {names}
|
||||
|
||||
@ -112,7 +112,7 @@ export function bashToolUseOptions({
|
||||
// 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.
|
||||
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({
|
||||
type: 'input',
|
||||
label: 'Yes, and don\u2019t ask again for',
|
||||
|
||||
@ -96,7 +96,7 @@ export function shouldHideTasksFooter(tasks: {
|
||||
if (!showSpinnerTree) return false;
|
||||
let hasVisibleTask = false;
|
||||
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;
|
||||
}
|
||||
hasVisibleTask = true;
|
||||
|
||||
47
src/main.tsx
47
src/main.tsx
@ -262,13 +262,10 @@ function isBeingDebugged() {
|
||||
}
|
||||
}
|
||||
|
||||
// Exit if we detect node debugging or inspection
|
||||
if (("external" as string) !== 'ant' && isBeingDebugged()) {
|
||||
// Use process.exit directly here since we're in the top-level code before imports
|
||||
// and gracefulShutdown is not yet available
|
||||
// eslint-disable-next-line custom-rules/no-top-level-side-effects
|
||||
process.exit(1);
|
||||
}
|
||||
// Anti-debugging check disabled for local development
|
||||
// if ((process.env.USER_TYPE) !== 'ant' && isBeingDebugged()) {
|
||||
// process.exit(1);
|
||||
// }
|
||||
|
||||
/**
|
||||
* Per-session skill/plugin telemetry. Called from both the interactive path
|
||||
@ -337,7 +334,7 @@ function runMigrations(): void {
|
||||
if (feature('TRANSCRIPT_CLASSIFIER')) {
|
||||
resetAutoModeOptInForDefaultOffer();
|
||||
}
|
||||
if (("external" as string) === 'ant') {
|
||||
if ((process.env.USER_TYPE) === 'ant') {
|
||||
migrateFennecToOpus();
|
||||
}
|
||||
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
|
||||
if (("external" as string) === 'ant') {
|
||||
if ((process.env.USER_TYPE) === 'ant') {
|
||||
void import('./utils/eventLoopStallDetector.js').then(m => m.startEventLoopStallDetector());
|
||||
}
|
||||
}
|
||||
@ -1134,11 +1131,11 @@ async function run(): Promise<CommanderCommand> {
|
||||
const disableSlashCommands = options.disableSlashCommands || false;
|
||||
|
||||
// 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;
|
||||
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;
|
||||
}
|
||||
|
||||
@ -1528,7 +1525,7 @@ async function run(): Promise<CommanderCommand> {
|
||||
};
|
||||
// Store the explicit CLI flag so teammates can inherit it
|
||||
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();
|
||||
if (enableClaudeInChrome) {
|
||||
const platform = getPlatform();
|
||||
@ -1760,7 +1757,7 @@ async function run(): Promise<CommanderCommand> {
|
||||
} = initResult;
|
||||
|
||||
// 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) {
|
||||
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)
|
||||
// - flag absent from disk (== null also catches pre-#22279 poisoned null)
|
||||
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();
|
||||
}
|
||||
|
||||
@ -2156,7 +2153,7 @@ async function run(): Promise<CommanderCommand> {
|
||||
// Log agent memory loaded event for tmux teammates
|
||||
if (customAgent.memory) {
|
||||
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
|
||||
}),
|
||||
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;
|
||||
stats = ctx.stats;
|
||||
// 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();
|
||||
}
|
||||
const {
|
||||
@ -2816,7 +2813,7 @@ async function run(): Promise<CommanderCommand> {
|
||||
if (!isBareMode()) {
|
||||
startDeferredPrefetches();
|
||||
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());
|
||||
}
|
||||
}
|
||||
@ -3061,7 +3058,7 @@ async function run(): Promise<CommanderCommand> {
|
||||
// - Runtime: uploader checks github.com/anthropics/* remote + gcloud auth.
|
||||
// - Safety: CLAUDE_CODE_DISABLE_SESSION_DATA_UPLOAD=1 bypasses (tests set this).
|
||||
// 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
|
||||
// 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) {
|
||||
// Check for ccshare URL (e.g. https://go/ccshare/boris-20260311-211036)
|
||||
const {
|
||||
@ -3813,7 +3810,7 @@ async function run(): Promise<CommanderCommand> {
|
||||
if (canUserConfigureAdvisor()) {
|
||||
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({
|
||||
permissionMode: 'auto'
|
||||
}));
|
||||
@ -4367,7 +4364,7 @@ async function run(): Promise<CommanderCommand> {
|
||||
});
|
||||
|
||||
// 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 () => {
|
||||
const {
|
||||
up
|
||||
@ -4378,7 +4375,7 @@ async function run(): Promise<CommanderCommand> {
|
||||
|
||||
// claude rollback (ant-only)
|
||||
// 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?: {
|
||||
list?: boolean;
|
||||
dryRun?: boolean;
|
||||
@ -4402,7 +4399,7 @@ async function run(): Promise<CommanderCommand> {
|
||||
});
|
||||
|
||||
// ant-only commands
|
||||
if (("external" as string) === 'ant') {
|
||||
if ((process.env.USER_TYPE) === 'ant') {
|
||||
const validateLogId = (value: string) => {
|
||||
const maybeSessionId = validateUuid(value);
|
||||
if (maybeSessionId) return maybeSessionId;
|
||||
@ -4436,7 +4433,7 @@ Examples:
|
||||
} = await import('./cli/handlers/ant.js');
|
||||
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');
|
||||
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;
|
||||
@ -4595,7 +4592,7 @@ async function logTenguInit({
|
||||
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,
|
||||
...(("external" as string) === 'ant' ? (() => {
|
||||
...((process.env.USER_TYPE) === 'ant' ? (() => {
|
||||
const cwd = getCwd();
|
||||
const gitRoot = findGitRoot(cwd);
|
||||
const rp = gitRoot ? relative(gitRoot, cwd) || '.' : undefined;
|
||||
|
||||
@ -104,13 +104,13 @@ const VoiceKeybindingHandler: typeof import('../hooks/useVoiceIntegration.js').V
|
||||
// Frustration detection is ant-only (dogfooding). Conditional require so external
|
||||
// builds eliminate the module entirely (including its two O(n) useMemos that run
|
||||
// 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',
|
||||
handleTranscriptSelect: () => {}
|
||||
});
|
||||
// Ant-only org warning. Conditional require so the org UUID list is
|
||||
// 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
|
||||
const getCoordinatorUserContext: (mcpClients: ReadonlyArray<{
|
||||
name: string;
|
||||
@ -219,9 +219,9 @@ import { EffortCallout, shouldShowEffortCallout } from '../components/EffortCall
|
||||
import type { EffortValue } from '../utils/effort.js';
|
||||
import { RemoteCallout } from '../components/RemoteCallout.js';
|
||||
/* 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 shouldShowAntModelSwitch = ("external" as string) === 'ant' ? require('../components/AntModelSwitchCallout.js').shouldShowModelSwitchCallout : (): boolean => false;
|
||||
const UndercoverAutoCallout = ("external" as string) === 'ant' ? require('../components/UndercoverAutoCallout.js').UndercoverAutoCallout : null;
|
||||
const AntModelSwitchCallout = (process.env.USER_TYPE) === 'ant' ? require('../components/AntModelSwitchCallout.js').AntModelSwitchCallout : null;
|
||||
const shouldShowAntModelSwitch = (process.env.USER_TYPE) === 'ant' ? require('../components/AntModelSwitchCallout.js').shouldShowModelSwitchCallout : (): boolean => false;
|
||||
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 */
|
||||
import { activityManager } from '../utils/activityManager.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+
|
||||
// includes, and these were on the render path (hot during PageUp spam).
|
||||
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 disableMessageActions = feature('MESSAGE_ACTIONS') ?
|
||||
// biome-ignore lint/correctness/useHookAtTopLevel: feature() is a compile-time constant
|
||||
@ -734,7 +734,7 @@ export function REPL({
|
||||
const [showIdeOnboarding, setShowIdeOnboarding] = useState(false);
|
||||
// Dead code elimination: model switch callout state (ant-only)
|
||||
const [showModelSwitchCallout, setShowModelSwitchCallout] = useState(() => {
|
||||
if (("external" as string) === 'ant') {
|
||||
if ((process.env.USER_TYPE) === 'ant') {
|
||||
return shouldShowAntModelSwitch();
|
||||
}
|
||||
return false;
|
||||
@ -1013,7 +1013,7 @@ export function REPL({
|
||||
}, []);
|
||||
const [showUndercoverCallout, setShowUndercoverCallout] = useState(false);
|
||||
useEffect(() => {
|
||||
if (("external" as string) === 'ant') {
|
||||
if ((process.env.USER_TYPE) === 'ant') {
|
||||
void (async () => {
|
||||
// Wait for repo classification to settle (memoized, no-op if primed).
|
||||
const {
|
||||
@ -2045,10 +2045,10 @@ export function REPL({
|
||||
if (allowDialogsWithAnimation && showIdeOnboarding) return 'ide-onboarding';
|
||||
|
||||
// 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)
|
||||
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)
|
||||
if (allowDialogsWithAnimation && showEffortCallout) return 'effort-callout';
|
||||
@ -2486,7 +2486,7 @@ export function REPL({
|
||||
dynamicSkillDirTriggers: new Set<string>(),
|
||||
discoveredSkillNames: discoveredSkillNamesRef.current,
|
||||
setResponseLength,
|
||||
pushApiMetricsEntry: ("external" as string) === 'ant' ? (ttftMs: number) => {
|
||||
pushApiMetricsEntry: (process.env.USER_TYPE) === 'ant' ? (ttftMs: number) => {
|
||||
const now = Date.now();
|
||||
const baseline = responseLengthRef.current;
|
||||
apiMetricsRef.current.push({
|
||||
@ -2815,7 +2815,7 @@ export function REPL({
|
||||
|
||||
// Capture ant-only API metrics before resetLoadingState clears the ref.
|
||||
// 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 ttfts = entries.map(e => e.ttftMs);
|
||||
// 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
|
||||
// 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).
|
||||
if (("external" as string) === 'ant' && !abortController.signal.aborted) {
|
||||
if ((process.env.USER_TYPE) === 'ant' && !abortController.signal.aborted) {
|
||||
setAppState(prev => {
|
||||
if (prev.tungstenActiveSession === undefined) 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
|
||||
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 => {
|
||||
// Build and apply permission updates (mode + allowedPrompts rules)
|
||||
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
|
||||
const handleSurveyRequestFeedback = useCallback(() => {
|
||||
const command = ("external" as string) === 'ant' ? '/issue' : '/feedback';
|
||||
const command = (process.env.USER_TYPE) === 'ant' ? '/issue' : '/feedback';
|
||||
onSubmit(command, {
|
||||
setCursorOffset: () => {},
|
||||
clearBuffer: () => {},
|
||||
@ -4060,7 +4060,7 @@ export function REPL({
|
||||
// - Workers receive permission responses 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
|
||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||
// 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
|
||||
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 label = cmd ? ` '${truncateToWidth(cmd, 40)}'` : '';
|
||||
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.jsx}
|
||||
</Box>}
|
||||
{("external" as string) === 'ant' && <TungstenLiveMonitor />}
|
||||
{(process.env.USER_TYPE) === 'ant' && <TungstenLiveMonitor />}
|
||||
{feature('WEB_BROWSER_TOOL') ? WebBrowserPanelModule && <WebBrowserPanelModule.WebBrowserPanel /> : null}
|
||||
<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} />}
|
||||
@ -4801,7 +4801,7 @@ export function REPL({
|
||||
});
|
||||
}} />}
|
||||
{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);
|
||||
if (selection === 'switch' && modelAlias) {
|
||||
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 => {
|
||||
setShowEffortCallout(false);
|
||||
if (selection !== 'dismiss') {
|
||||
@ -4894,7 +4894,7 @@ export function REPL({
|
||||
{/* Frustration-triggered transcript sharing prompt */}
|
||||
{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) */}
|
||||
{("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 />}
|
||||
{}
|
||||
<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);
|
||||
setMessageSelectorPreselect(undefined);
|
||||
}} />}
|
||||
{("external" as string) === 'ant' && <DevBar />}
|
||||
{(process.env.USER_TYPE) === 'ant' && <DevBar />}
|
||||
</Box>
|
||||
{feature('BUDDY') && !(companionNarrow && isFullscreenEnvEnabled()) && companionVisible ? <CompanionSprite /> : null}
|
||||
</Box>} />
|
||||
|
||||
@ -96,7 +96,7 @@ const fullInputSchema = lazySchema(() => {
|
||||
mode: permissionModeSchema().optional().describe('Permission mode for spawned teammate (e.g., "plan" to require plan approval).')
|
||||
});
|
||||
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".')
|
||||
});
|
||||
});
|
||||
@ -432,7 +432,7 @@ export const AgentTool = buildTool({
|
||||
|
||||
// Remote isolation: delegate to CCR. Gated ant-only — the guard enables
|
||||
// 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();
|
||||
if (!eligibility.eligible) {
|
||||
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
|
||||
if (selectedAgent.memory) {
|
||||
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
|
||||
}),
|
||||
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
|
||||
// In all other modes, auto-approve sub-agent generation
|
||||
// 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 {
|
||||
behavior: 'passthrough',
|
||||
message: 'Agent tool requires permission to spawn sub-agents.'
|
||||
|
||||
@ -99,7 +99,7 @@ type ProcessedMessage = {
|
||||
*/
|
||||
function processProgressMessages(messages: ProgressMessage<Progress>[], tools: Tools, isAgentRunning: boolean): ProcessedMessage[] {
|
||||
// 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 => ({
|
||||
type: 'original',
|
||||
message: m
|
||||
@ -385,7 +385,7 @@ export function renderToolResultMessage(data: Output, progressMessagesForMessage
|
||||
} as import('@anthropic-ai/sdk/resources/beta/messages/messages.mjs').BetaUsage
|
||||
});
|
||||
return <Box flexDirection="column">
|
||||
{("external" as string) === 'ant' && <MessageResponse>
|
||||
{(process.env.USER_TYPE) === 'ant' && <MessageResponse>
|
||||
<Text color="warning">
|
||||
[ANT-ONLY] API calls: {getDisplayPath(getDumpPromptsPath(agentId))}
|
||||
</Text>
|
||||
@ -591,7 +591,7 @@ export function renderToolUseRejectedMessage(_input: {
|
||||
const firstData = progressMessagesForMessage[0]?.data;
|
||||
const agentId = firstData && hasProgressMessage(firstData) ? firstData.agentId : undefined;
|
||||
return <>
|
||||
{("external" as string) === 'ant' && agentId && <MessageResponse>
|
||||
{(process.env.USER_TYPE) === 'ant' && agentId && <MessageResponse>
|
||||
<Text color="warning">
|
||||
[ANT-ONLY] API calls: {getDisplayPath(getDumpPromptsPath(agentId))}
|
||||
</Text>
|
||||
|
||||
@ -161,7 +161,7 @@ export const TaskOutputTool: Tool<InputSchema, TaskOutputToolOutput> = buildTool
|
||||
return this.isReadOnly?.(_input) ?? false;
|
||||
},
|
||||
isEnabled() {
|
||||
return ("external" as string) !== 'ant';
|
||||
return (process.env.USER_TYPE) !== 'ant';
|
||||
},
|
||||
isReadOnly(_input) {
|
||||
return true;
|
||||
|
||||
@ -25,7 +25,7 @@ export function renderToolResultMessage(output: Output, _progressMessagesForMess
|
||||
}: {
|
||||
verbose: boolean;
|
||||
}): React.ReactNode {
|
||||
if (("external" as string) === 'ant') {
|
||||
if ((process.env.USER_TYPE) === 'ant') {
|
||||
return null;
|
||||
}
|
||||
const rawCommand = output.command ?? '';
|
||||
|
||||
@ -81,7 +81,7 @@ export type AutoRunIssueReason = 'feedback_survey_bad' | 'feedback_survey_good';
|
||||
*/
|
||||
export function shouldAutoRunIssue(reason: AutoRunIssueReason): boolean {
|
||||
// Only for Ant users
|
||||
if (("external" as string) !== 'ant') {
|
||||
if ((process.env.USER_TYPE) !== 'ant') {
|
||||
return false;
|
||||
}
|
||||
switch (reason) {
|
||||
@ -100,7 +100,7 @@ export function shouldAutoRunIssue(reason: AutoRunIssueReason): boolean {
|
||||
*/
|
||||
export function getAutoRunCommand(reason: AutoRunIssueReason): string {
|
||||
// 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 '/issue';
|
||||
|
||||
@ -273,7 +273,7 @@ async function executeForkedSlashCommand(command: CommandBase & PromptCommand, a
|
||||
logForDebugging(`Forked slash command /${command.name} completed with agent ${agentId}`);
|
||||
|
||||
// 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}`;
|
||||
}
|
||||
|
||||
@ -427,7 +427,7 @@ export async function processSlashCommand(inputString: string, precedingInputBlo
|
||||
logEvent('tengu_input_command', {
|
||||
...eventData,
|
||||
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,
|
||||
...(returnedCommand.type === 'prompt' && {
|
||||
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', {
|
||||
...eventData,
|
||||
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,
|
||||
...(returnedCommand.type === 'prompt' && {
|
||||
skill_source: returnedCommand.source as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS
|
||||
|
||||
@ -26,7 +26,7 @@ export type Property = {
|
||||
};
|
||||
export type Diagnostic = React.ReactNode;
|
||||
export function buildSandboxProperties(): Property[] {
|
||||
if (("external" as string) !== 'ant') {
|
||||
if ((process.env.USER_TYPE) !== 'ant') {
|
||||
return [];
|
||||
}
|
||||
const isSandboxed = SandboxManager.isSandboxingEnabled();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user