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.
|
// 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;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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} />;
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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()}`;
|
||||||
|
|||||||
@ -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: `~10–30 min · Claude Code on the web drafts an advanced plan you can edit and approve. See ${CCR_TERMS_URL}`,
|
description: `~10–30 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
|
||||||
})
|
})
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
@ -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[];
|
||||||
|
|||||||
@ -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') {
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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',
|
||||||
|
|||||||
@ -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 · Try <Text bold>/status</Text>
|
✗ Auto-update failed · 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} · Run{' '}
|
⚠ Known issue: {maxVersionIssue} · Run{' '}
|
||||||
<Text bold>claude rollback --safe</Text> to downgrade
|
<Text bold>claude rollback --safe</Text> to downgrade
|
||||||
</Text>}
|
</Text>}
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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,
|
||||||
|
|||||||
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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)));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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',
|
||||||
|
|||||||
@ -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}
|
||||||
|
|||||||
@ -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',
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
47
src/main.tsx
47
src/main.tsx
@ -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;
|
||||||
|
|||||||
@ -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>} />
|
||||||
|
|||||||
@ -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.'
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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 ?? '';
|
||||||
|
|||||||
@ -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';
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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();
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user