cleanup: remove dead USER_TYPE fast mode and setup branches (#315)
This commit is contained in:
40
src/setup.ts
40
src/setup.ts
@@ -6,7 +6,6 @@ import {
|
||||
type AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
|
||||
logEvent,
|
||||
} from 'src/services/analytics/index.js'
|
||||
import { isAntEmployee } from 'src/utils/buildConfig.js'
|
||||
import { getCwd } from 'src/utils/cwd.js'
|
||||
import { checkForReleaseNotes } from 'src/utils/releaseNotes.js'
|
||||
import { setCwd } from 'src/utils/Shell.js'
|
||||
@@ -335,19 +334,6 @@ export async function setup(
|
||||
// overhead. NOT an early-return: the --dangerously-skip-permissions safety
|
||||
// gate, tengu_started beacon, and apiKeyHelper prefetch below must still run.
|
||||
if (!isBareMode()) {
|
||||
if (isAntEmployee()) {
|
||||
// Prime repo classification cache for auto-undercover mode. Default is
|
||||
// undercover ON until proven internal; if this resolves to internal, clear
|
||||
// the prompt cache so the next turn picks up the OFF state.
|
||||
void import('./utils/commitAttribution.js').then(async m => {
|
||||
if (await m.isInternalModelRepo()) {
|
||||
const { clearSystemPromptSections } = await import(
|
||||
'./constants/systemPromptSections.js'
|
||||
)
|
||||
clearSystemPromptSections()
|
||||
}
|
||||
})
|
||||
}
|
||||
if (feature('COMMIT_ATTRIBUTION')) {
|
||||
// Dynamic import to enable dead code elimination (module contains excluded strings).
|
||||
// Defer to next tick so the git subprocess spawn runs after first render
|
||||
@@ -414,32 +400,6 @@ export async function setup(
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
if (
|
||||
isAntEmployee() &&
|
||||
// Skip for Desktop's local agent mode — same trust model as CCR/BYOC
|
||||
// (trusted Anthropic-managed launcher intentionally pre-approving everything).
|
||||
// Precedent: permissionSetup.ts:861, applySettingsChange.ts:55 (PR #19116)
|
||||
process.env.CLAUDE_CODE_ENTRYPOINT !== 'local-agent' &&
|
||||
// Same for CCD (Claude Code in Desktop) — apps#29127 passes the flag
|
||||
// unconditionally to unlock mid-session bypass switching
|
||||
process.env.CLAUDE_CODE_ENTRYPOINT !== 'claude-desktop'
|
||||
) {
|
||||
// Only await if permission mode is set to bypass
|
||||
const [isDocker, hasInternet] = await Promise.all([
|
||||
envDynamic.getIsDocker(),
|
||||
env.hasInternetAccess(),
|
||||
])
|
||||
const isBubblewrap = envDynamic.getIsBubblewrapSandbox()
|
||||
const isSandbox = process.env.IS_SANDBOX === '1'
|
||||
const isSandboxed = isDocker || isBubblewrap || isSandbox
|
||||
if (!isSandboxed || hasInternet) {
|
||||
// biome-ignore lint/suspicious/noConsole:: intentional console output
|
||||
console.error(
|
||||
`--dangerously-skip-permissions can only be used in Docker/sandbox containers with no internet access but got Docker: ${isDocker}, Bubblewrap: ${isBubblewrap}, IS_SANDBOX: ${isSandbox}, hasInternet: ${hasInternet}`,
|
||||
)
|
||||
process.exit(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (process.env.NODE_ENV === 'test') {
|
||||
|
||||
162
src/utils/fastMode.test.ts
Normal file
162
src/utils/fastMode.test.ts
Normal file
@@ -0,0 +1,162 @@
|
||||
import { afterEach, describe, expect, mock, test } from 'bun:test'
|
||||
|
||||
const originalEnv = { ...process.env }
|
||||
|
||||
async function importFreshFastModeModule() {
|
||||
return import(`./fastMode.ts?ts=${Date.now()}-${Math.random()}`)
|
||||
}
|
||||
|
||||
function installCommonMocks(options?: {
|
||||
cachedEnabled?: boolean
|
||||
apiKey?: string | null
|
||||
oauthToken?: string | null
|
||||
hasProfileScope?: boolean
|
||||
axiosReject?: boolean
|
||||
}) {
|
||||
mock.module('axios', () => ({
|
||||
default: {
|
||||
get: options?.axiosReject
|
||||
? async () => {
|
||||
throw new Error('network fail')
|
||||
}
|
||||
: async () => ({ data: { enabled: false, disabled_reason: 'preference' } }),
|
||||
isAxiosError: () => false,
|
||||
},
|
||||
}))
|
||||
|
||||
mock.module('src/constants/oauth.js', () => ({
|
||||
getOauthConfig: () => ({ BASE_API_URL: 'https://api.anthropic.com' }),
|
||||
OAUTH_BETA_HEADER: 'test-beta',
|
||||
}))
|
||||
|
||||
mock.module('src/services/analytics/growthbook.js', () => ({
|
||||
getFeatureValue_CACHED_MAY_BE_STALE: (_name: string, defaultValue: unknown) =>
|
||||
defaultValue,
|
||||
}))
|
||||
|
||||
mock.module('../bootstrap/state.js', () => ({
|
||||
getIsNonInteractiveSession: () => false,
|
||||
getKairosActive: () => false,
|
||||
preferThirdPartyAuthentication: () => false,
|
||||
}))
|
||||
|
||||
mock.module('../services/analytics/index.js', () => ({
|
||||
logEvent: () => {},
|
||||
}))
|
||||
|
||||
mock.module('./auth.js', () => ({
|
||||
getAnthropicApiKey: () => options?.apiKey ?? null,
|
||||
getClaudeAIOAuthTokens: () =>
|
||||
options?.oauthToken ? { accessToken: options.oauthToken } : null,
|
||||
handleOAuth401Error: async () => {},
|
||||
hasProfileScope: () => options?.hasProfileScope ?? false,
|
||||
}))
|
||||
|
||||
mock.module('./bundledMode.js', () => ({
|
||||
isInBundledMode: () => true,
|
||||
}))
|
||||
|
||||
mock.module('./config.js', () => ({
|
||||
getGlobalConfig: () => ({
|
||||
penguinModeOrgEnabled: options?.cachedEnabled === true,
|
||||
}),
|
||||
saveGlobalConfig: (updater: (current: Record<string, unknown>) => Record<string, unknown>) =>
|
||||
updater({ penguinModeOrgEnabled: options?.cachedEnabled === true }),
|
||||
}))
|
||||
|
||||
mock.module('./debug.js', () => ({
|
||||
logForDebugging: () => {},
|
||||
}))
|
||||
|
||||
mock.module('./envUtils.js', () => ({
|
||||
isEnvTruthy: (value: string | undefined) =>
|
||||
!!value && value !== '0' && value.toLowerCase() !== 'false',
|
||||
}))
|
||||
|
||||
mock.module('./model/model.js', () => ({
|
||||
getDefaultMainLoopModelSetting: () => 'claude-sonnet-4-6',
|
||||
isOpus1mMergeEnabled: () => false,
|
||||
parseUserSpecifiedModel: (model: string) => model,
|
||||
}))
|
||||
|
||||
mock.module('./model/providers.js', () => ({
|
||||
getAPIProvider: () => 'firstParty',
|
||||
}))
|
||||
|
||||
mock.module('./privacyLevel.js', () => ({
|
||||
isEssentialTrafficOnly: () => false,
|
||||
}))
|
||||
|
||||
mock.module('./settings/settings.js', () => ({
|
||||
getInitialSettings: () => ({ fastMode: true }),
|
||||
getSettingsForSource: () => ({}),
|
||||
updateSettingsForSource: () => {},
|
||||
}))
|
||||
|
||||
mock.module('./signal.js', () => ({
|
||||
createSignal: () => {
|
||||
const subscribe = () => () => {}
|
||||
const emit = () => {}
|
||||
return { subscribe, emit }
|
||||
},
|
||||
}))
|
||||
}
|
||||
|
||||
afterEach(() => {
|
||||
mock.restore()
|
||||
process.env = { ...originalEnv }
|
||||
})
|
||||
|
||||
describe('fastMode ant-only fallback cleanup', () => {
|
||||
test('resolveFastModeStatusFromCache does not force-enable from USER_TYPE=ant', async () => {
|
||||
process.env.USER_TYPE = 'ant'
|
||||
installCommonMocks({ cachedEnabled: false })
|
||||
|
||||
const {
|
||||
resolveFastModeStatusFromCache,
|
||||
getFastModeUnavailableReason,
|
||||
} = await importFreshFastModeModule()
|
||||
|
||||
resolveFastModeStatusFromCache()
|
||||
|
||||
expect(getFastModeUnavailableReason()).toBe(
|
||||
'Fast mode is currently unavailable',
|
||||
)
|
||||
})
|
||||
|
||||
test('prefetchFastModeStatus without auth does not force-enable from USER_TYPE=ant', async () => {
|
||||
process.env.USER_TYPE = 'ant'
|
||||
installCommonMocks({ cachedEnabled: false, apiKey: null, oauthToken: null })
|
||||
|
||||
const {
|
||||
prefetchFastModeStatus,
|
||||
getFastModeUnavailableReason,
|
||||
} = await importFreshFastModeModule()
|
||||
|
||||
await prefetchFastModeStatus()
|
||||
|
||||
expect(getFastModeUnavailableReason()).toBe(
|
||||
'Fast mode has been disabled by your organization',
|
||||
)
|
||||
})
|
||||
|
||||
test('prefetchFastModeStatus network failure does not force-enable from USER_TYPE=ant', async () => {
|
||||
process.env.USER_TYPE = 'ant'
|
||||
installCommonMocks({
|
||||
cachedEnabled: false,
|
||||
apiKey: 'test-key',
|
||||
axiosReject: true,
|
||||
})
|
||||
|
||||
const {
|
||||
prefetchFastModeStatus,
|
||||
getFastModeUnavailableReason,
|
||||
} = await importFreshFastModeModule()
|
||||
|
||||
await prefetchFastModeStatus()
|
||||
|
||||
expect(getFastModeUnavailableReason()).toBe(
|
||||
'Fast mode unavailable due to network connectivity issues',
|
||||
)
|
||||
})
|
||||
})
|
||||
@@ -396,10 +396,9 @@ export function resolveFastModeStatusFromCache(): void {
|
||||
if (orgStatus.status !== 'pending') {
|
||||
return
|
||||
}
|
||||
const isAnt = process.env.USER_TYPE === 'ant'
|
||||
const cachedEnabled = getGlobalConfig().penguinModeOrgEnabled === true
|
||||
orgStatus =
|
||||
isAnt || cachedEnabled
|
||||
cachedEnabled
|
||||
? { status: 'enabled' }
|
||||
: { status: 'disabled', reason: 'unknown' }
|
||||
}
|
||||
@@ -428,10 +427,9 @@ export async function prefetchFastModeStatus(): Promise<void> {
|
||||
const hasUsableOAuth =
|
||||
getClaudeAIOAuthTokens()?.accessToken && hasProfileScope()
|
||||
if (!hasUsableOAuth && !apiKey) {
|
||||
const isAnt = process.env.USER_TYPE === 'ant'
|
||||
const cachedEnabled = getGlobalConfig().penguinModeOrgEnabled === true
|
||||
orgStatus =
|
||||
isAnt || cachedEnabled
|
||||
cachedEnabled
|
||||
? { status: 'enabled' }
|
||||
: { status: 'disabled', reason: 'preference' }
|
||||
return
|
||||
@@ -511,10 +509,9 @@ export async function prefetchFastModeStatus(): Promise<void> {
|
||||
// On failure: ants default to enabled (don't block internal users).
|
||||
// External users: fall back to the cached penguinModeOrgEnabled value;
|
||||
// if no positive cache, disable with network_error reason.
|
||||
const isAnt = process.env.USER_TYPE === 'ant'
|
||||
const cachedEnabled = getGlobalConfig().penguinModeOrgEnabled === true
|
||||
orgStatus =
|
||||
isAnt || cachedEnabled
|
||||
cachedEnabled
|
||||
? { status: 'enabled' }
|
||||
: { status: 'disabled', reason: 'network_error' }
|
||||
logForDebugging(
|
||||
|
||||
Reference in New Issue
Block a user